/*
Theme Name: Hello Elementor Child
Theme URI: https://github.com/elementor/hello-theme-child/
Description: Hello Elementor Child is a child theme of Hello Elementor, created by Elementor team
Author: Elementor Team
Author URI: https://elementor.com/
Template: hello-elementor
Version: 2.0.0
Text Domain: hello-elementor-child
License: GNU General Public License v3 or later.
License URI: https://www.gnu.org/licenses/gpl-3.0.html
Tags: flexible-header, custom-colors, custom-menu, custom-logo, editor-style, featured-images, rtl-language-support, threaded-comments, translation-ready
*/

/* ============================================================
   MOVE, WordPress port of the static site stylesheet.
   Source: Website/move-website-static/assets/css/site.css, v1.7.3.1.
   Built by .foreman/scratch/wp-build/build-style.py. Do not hand
   edit this file above the Elementor glue section: edit site.css
   or glue.css and rebuild, or the next rebuild will discard it.

   Four changes were made to the source, and only these four:

     1. The @font-face block is gone. Plus Jakarta Sans now comes
        from the Elementor kit, which loads it from Google Fonts.
        --mv-font is unchanged and still names the same family.
     2. .mv-container--narrow is gone. It has been unused sitewide
        since v1.6.5b4 and would only invite a page worker to
        reach for it.
     3. Section 25, the justification rule, is scoped to .mv-band
        instead of main. In WordPress the header, the top bar, the
        announcement bar and the footer are Theme Builder
        templates that may or may not sit inside <main>, and the
        bands are the only thing that should ever be justified.
        Captions and source blocks were added to the ragged list
        because in the builder they arrive as paragraphs.
     4. The two hero drawings are referenced from the theme's own
        assets/img/ folder instead of ../img/, because this file
        no longer sits next to them.

   Everything else is byte for byte the stylesheet the client
   approved. Section 38 at the foot is new and is additive only.
   ============================================================ */

/* ============================================================
   MOVE website draft v1.0, site.css
   Built from approved Wireframe 2 + Mood Board 2, August 2026.
   One stylesheet for all pages. Class prefix: mv-
   Works from file://, relative paths only, no network requests.
   ------------------------------------------------------------
   1  Fonts
   2  Tokens
   3  Reset and base
   4  Typography
   5  Layout and bands
   6  Header and navigation
   7  Footer
   8  Buttons and links
   9  Cards
   10 Note and status boxes
   11 Stats and counts
   12 Lists (dash, beats, meta)
   13 Photos and figures
   14 Tables
   15 Forms
   16 Search band and chips
   17 Pathway cards
   18 Question cards and Q and A blocks
   19 Reference rail and citation
   20 MOVE on air panel
   21 Utilities
   22 Reference components (v1.2)
   22a v1.4 hero and card-link updates
   23 Narrow screens
   24 Reduced motion
   ============================================================ */

/* ---------- 1. Fonts ---------- */
/* Plus Jakarta Sans is loaded by the Elementor kit (Google Fonts), so the
   four @font-face rules the static build carried are gone. --mv-font below
   still names the same family and is still what every rule in this file
   asks for, so nothing downstream changes. */

/* ---------- 2. Tokens ---------- */
:root {
  /* palette, from the approved mood board */
  --mv-cream: #FAF6EF;
  --mv-sand: #EFE6D6;
  --mv-charcoal: #2A2724;
  --mv-brown: #6B5F52;
  --mv-red: #D93A2B;
  --mv-red-deep: #B7302A;
  --mv-red-light: #F2A79B;
  --mv-line: #E4D9C6;
  --mv-line-sand: #DFCFB4;
  --mv-line-dark: #46413B;
  --mv-card-dark: #3A3531;
  --mv-soft-dark: #C9BEB0;
  --mv-wash: #C97E38;
  --mv-white: #FFFFFF;

  --mv-radius: 10px;
  --mv-font: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mv-maxw: 1140px;
  --mv-pad: 24px;

  /* spacing scale */
  --mv-s1: 8px;
  --mv-s2: 12px;
  --mv-s3: 16px;
  --mv-s4: 24px;
  --mv-s5: 32px;
  --mv-s6: 48px;
  --mv-s7: 64px;
  --mv-s8: 96px;

  /* contextual tones, re-pointed by band modifiers */
  --mv-bg: var(--mv-cream);
  --mv-ink: var(--mv-charcoal);
  --mv-soft: var(--mv-brown);
  --mv-accent: var(--mv-red-deep);
  --mv-rule: var(--mv-line);
  --mv-card: var(--mv-sand);
  --mv-focus: var(--mv-charcoal);
}

/* ---------- 3. Reset and base ---------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--mv-cream);
  color: var(--mv-charcoal);
  font-family: var(--mv-font);
  font-size: 17px;
  font-weight: 400;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; display: block; }

a { color: var(--mv-accent); }

button, input, select, textarea { font: inherit; color: inherit; }

h1, h2, h3, h4 { margin: 0 0 var(--mv-s2); }
p { margin: 0 0 var(--mv-s3); }
p:last-child { margin-bottom: 0; }

ul, ol { margin: 0 0 var(--mv-s3); padding-left: 20px; }

:focus-visible {
  outline: 2px solid var(--mv-focus);
  outline-offset: 3px;
}

.mv-skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 60;
  background: var(--mv-charcoal);
  color: var(--mv-cream);
  padding: 12px 18px;
  border-radius: 0 0 var(--mv-radius) 0;
  font-weight: 700;
  text-decoration: none;
}
.mv-skip:focus { left: 0; }

/* ---------- 4. Typography ---------- */
.mv-display,
h1.mv-display {
  font-weight: 800;
  font-size: clamp(38px, 5.4vw, 58px);
  line-height: 1.05;
  letter-spacing: -0.03em;
  margin: 0 0 var(--mv-s4);
  max-width: 20ch;
}
.mv-display--sm { font-size: clamp(30px, 3.9vw, 44px); max-width: 24ch; }

.mv-h2, h2 {
  font-weight: 800;
  font-size: clamp(28px, 3.6vw, 40px);
  line-height: 1.1;
  letter-spacing: -0.03em;
}
h3 {
  font-weight: 800;
  font-size: 22px;
  line-height: 1.2;
  letter-spacing: -0.02em;
}
.mv-kicker {
  display: block;
  font-size: 12.5px;
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mv-accent);
  margin: 0 0 var(--mv-s2);
}
.mv-lede {
  font-size: 20px;
  line-height: 1.55;
  font-weight: 500;
  max-width: 60ch;
  margin: 0 0 var(--mv-s4);
}
.mv-lede--sm { font-size: 18px; font-weight: 400; }
/* Measure note (v1.2): 1ch in Plus Jakarta Sans is the width of "0", about 12px at 17px type,
   while the average lowercase character is about 9px. A 68ch max-width therefore sets roughly
   97 characters per line, well past the comfortable 45 to 75. The reference pages carry far
   more continuous prose than v1.0 did, so the prose measures below are tuned to land near 75. */
.mv-body { font-size: 17px; line-height: 1.6; max-width: 52ch; }
.mv-soft { color: var(--mv-soft); }
.mv-meta {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--mv-soft);
  margin: 0 0 var(--mv-s2);
}
.mv-fineprint {
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--mv-soft);
  max-width: 52ch;
}

/* ---------- 5. Layout and bands ---------- */
.mv-container {
  width: 100%;
  max-width: var(--mv-maxw);
  margin: 0 auto;
  padding: 0 var(--mv-pad);
}

.mv-band {
  background: var(--mv-bg);
  color: var(--mv-ink);
  padding: clamp(48px, 6vw, 80px) 0;
}
.mv-band--sand {
  --mv-bg: var(--mv-sand);
  --mv-rule: var(--mv-line-sand);
  --mv-card: var(--mv-cream);
}
.mv-band--white {
  --mv-bg: var(--mv-white);
  --mv-card: var(--mv-cream);
}
.mv-band--dark {
  --mv-bg: var(--mv-charcoal);
  --mv-ink: var(--mv-cream);
  --mv-soft: var(--mv-soft-dark);
  --mv-accent: var(--mv-red-light);
  --mv-rule: var(--mv-line-dark);
  --mv-card: var(--mv-card-dark);
  --mv-focus: var(--mv-cream);
}
.mv-band--slim { padding: clamp(40px, 4.4vw, 56px) 0; }

/* hairline only between two like-toned bands; a tone change is its own divider */
.mv-band + .mv-band { border-top: 1px solid var(--mv-rule); }
.mv-band--sand + .mv-band,
.mv-band + .mv-band--sand,
.mv-band--dark + .mv-band,
.mv-band + .mv-band--dark,
.mv-band--white + .mv-band,
.mv-band + .mv-band--white { border-top: 0; }

.mv-sechead {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--mv-s2) var(--mv-s4);
  margin-bottom: var(--mv-s4);
}
.mv-sechead h2 { margin-bottom: 0; }

.mv-cols-2,
.mv-cols-3,
.mv-cols-4 {
  display: grid;
  gap: var(--mv-s4);
}
.mv-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--mv-s6); }
.mv-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.mv-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.mv-split {
  display: grid;
  grid-template-columns: 1.04fr 0.96fr;
  align-items: stretch;
  gap: 0;
}
.mv-split--gap { gap: clamp(32px, 4vw, 56px); }

/* hero: copy stack beside a full-height photo */
.mv-hero { padding-top: clamp(40px, 4.6vw, 60px); }
.mv-hero__grid {
  display: grid;
  grid-template-columns: 1.06fr 0.94fr;
  gap: clamp(32px, 4vw, 56px);
  align-items: stretch;
}
.mv-hero__copy { align-self: start; }
.mv-hero__copy .mv-display { max-width: 17ch; }
.mv-hero__cards { display: grid; gap: var(--mv-s3); margin-top: var(--mv-s5); }
.mv-hero__photo { min-height: 100%; }

/* ---------- 6. Header and navigation ---------- */
.mv-header {
  background: var(--mv-cream);
  border-bottom: 1px solid var(--mv-line);
}
.mv-header__inner {
  display: flex;
  align-items: center;
  gap: var(--mv-s4);
  padding-top: 16px;
  padding-bottom: 16px;
}
.mv-brand {
  display: block;
  text-decoration: none;
  color: inherit;
  flex: 0 0 auto;
}
.mv-wordmark {
  display: block;
  font-weight: 800;
  font-size: 21px;
  line-height: 1.1;
  letter-spacing: 0.02em;
  color: var(--mv-red-deep);
}
.mv-brand__sub {
  display: block;
  font-size: 11px;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mv-brown);
  margin-top: 3px;
}

.mv-navtoggle {
  display: none;
  align-items: center;
  gap: 8px;
  margin-left: auto;
  min-height: 44px;
  padding: 0 14px;
  background: transparent;
  border: 1.5px solid var(--mv-charcoal);
  border-radius: 999px;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
}
.mv-navtoggle__bars {
  position: relative;
  display: block;
  width: 16px;
  height: 2px;
  background: var(--mv-charcoal);
}
.mv-navtoggle__bars::before,
.mv-navtoggle__bars::after {
  content: "";
  position: absolute;
  left: 0;
  width: 16px;
  height: 2px;
  background: var(--mv-charcoal);
}
.mv-navtoggle__bars::before { top: -5px; }
.mv-navtoggle__bars::after { top: 5px; }

.mv-nav {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex: 1 1 auto;
  gap: var(--mv-s4);
}
.mv-nav__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 18px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.mv-nav__list > li { position: relative; }
.mv-nav a,
.mv-dropdown__trigger {
  display: inline-block;
  padding: 6px 2px;
  background: transparent;
  border: 0;
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--mv-charcoal);
  text-decoration: none;
  cursor: pointer;
}
.mv-nav a:hover,
.mv-dropdown__trigger:hover { color: var(--mv-red-deep); }
.mv-nav__list > li > a[aria-current="page"],
.mv-nav__list > li > a[aria-current="true"],
.mv-dropdown__trigger.is-current {
  color: var(--mv-red-deep);
  border-bottom: 2px solid var(--mv-red-deep);
}
/* inside an open menu, mark the exact page without the section rule */
.mv-dropdown__menu a[aria-current="page"] { color: var(--mv-red-deep); font-weight: 700; }

.mv-dropdown__menu {
  position: absolute;
  top: calc(100% + 8px);
  left: -14px;
  z-index: 40;
  min-width: 220px;
  margin: 0;
  padding: 8px;
  list-style: none;
  background: var(--mv-cream);
  border: 1px solid var(--mv-line);
  border-radius: var(--mv-radius);
  box-shadow: 0 1px 2px rgba(42, 39, 36, .08), 0 14px 30px rgba(42, 39, 36, .12);
}
.mv-dropdown__menu[hidden] { display: none; }
.mv-dropdown__menu a {
  display: block;
  padding: 9px 12px;
  border-radius: 6px;
}
.mv-dropdown__menu a:hover { background: var(--mv-sand); }

.mv-lang {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  color: var(--mv-brown);
}
.mv-lang__btn {
  background: transparent;
  border: 0;
  padding: 4px 2px;
  font-size: 13px;
  font-weight: 700;
  color: var(--mv-brown);
}
.mv-lang__btn[disabled] { cursor: not-allowed; opacity: .7; }
.mv-lang__btn.is-active { color: var(--mv-red-deep); }

/* ---------- 7. Footer ---------- */
.mv-footer {
  background: var(--mv-charcoal);
  color: var(--mv-cream);
  --mv-focus: var(--mv-cream);
  padding: clamp(48px, 5vw, 64px) 0 var(--mv-s6);
}
.mv-footer__top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 3.2fr);
  gap: var(--mv-s6);
  padding-bottom: var(--mv-s6);
  border-bottom: 1px solid var(--mv-line-dark);
}
.mv-footer .mv-wordmark { color: var(--mv-cream); }
.mv-footer__line {
  margin-top: var(--mv-s2);
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--mv-soft-dark);
  max-width: 34ch;
}
.mv-footer__nav {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--mv-s5) var(--mv-s4);
}
.mv-footer__h {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mv-red-light);
  margin: 0 0 var(--mv-s2);
}
.mv-footer__list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.mv-footer__list li + li { margin-top: 8px; }
.mv-footer__list a {
  font-size: 15px;
  color: var(--mv-cream);
  text-decoration: none;
}
.mv-footer__list a:hover { text-decoration: underline; text-underline-offset: 4px; }
.mv-footer__notice {
  margin-top: var(--mv-s4);
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--mv-cream);
  max-width: 78ch;
}
.mv-footer__meta {
  margin-top: var(--mv-s2);
  font-size: 13.5px;
  color: var(--mv-soft-dark);
}

/* ---------- 8. Buttons and links ---------- */
.mv-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 0 26px;
  border: 1.5px solid transparent;
  border-radius: 999px;
  font-family: var(--mv-font);
  font-size: 16px;
  font-weight: 700;
  line-height: 1;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 150ms ease, border-color 150ms ease,
              color 150ms ease, transform 150ms ease;
}
.mv-btn--primary {
  background: var(--mv-red);
  color: var(--mv-white);
  box-shadow: 0 1px 2px rgba(42, 39, 36, .10), 0 8px 18px rgba(42, 39, 36, .10);
}
.mv-btn--primary:hover { background: var(--mv-red-deep); transform: translateY(-1px); }
.mv-btn--primary:active { transform: translateY(0) scale(.99); }
.mv-btn--ghost {
  background: transparent;
  border-color: var(--mv-ink);
  color: var(--mv-ink);
}
.mv-btn--ghost:hover { background: rgba(42, 39, 36, .06); transform: translateY(-1px); }
.mv-band--dark .mv-btn--ghost:hover { background: rgba(250, 246, 239, .10); }
.mv-btn--ghost:active { transform: translateY(0) scale(.99); }
.mv-btn:focus-visible { outline: 2px solid var(--mv-focus); outline-offset: 3px; }
.mv-btns {
  display: flex;
  flex-wrap: wrap;
  gap: var(--mv-s2);
  margin-top: var(--mv-s4);
}

.mv-link {
  display: inline-block;
  font-weight: 700;
  font-size: 15.5px;
  color: var(--mv-accent);
  text-decoration: underline;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 4px;
  transition: color 150ms ease;
}
.mv-link:hover { color: var(--mv-ink); }
.mv-link--card { margin-top: var(--mv-s3); }

/* ---------- 9. Cards ---------- */
.mv-card {
  background: var(--mv-card);
  border-radius: var(--mv-radius);
  padding: 26px 26px 24px;
}
.mv-card--line { border: 1px solid var(--mv-rule); }
.mv-card__kicker {
  display: block;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mv-accent);
  margin-bottom: 10px;
}
.mv-card__title {
  font-size: 23px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 0 0 10px;
}
.mv-card__title a { color: inherit; text-decoration: none; }
.mv-card__title a:hover { color: var(--mv-accent); }
.mv-card__body {
  font-size: 16px;
  line-height: 1.6;
  color: var(--mv-soft);
}
.mv-card__body p:last-child { margin-bottom: 0; }

/* pinned / flagship card, used for the commissioned study */
.mv-pinned {
  background: var(--mv-card);
  border-left: 3px solid var(--mv-red);
  border-radius: 0 var(--mv-radius) var(--mv-radius) 0;
  padding: 30px 32px;
}
.mv-flag {
  display: inline-block;
  margin-bottom: 12px;
  padding: 5px 12px;
  border-radius: 999px;
  background: var(--mv-red);
  color: var(--mv-white);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.mv-pinned h3 {
  font-size: clamp(23px, 2.5vw, 29px);
  line-height: 1.15;
  max-width: 26ch;
  margin-bottom: 8px;
}

/* notice card, for the 18+ line */
.mv-notice {
  background: var(--mv-card);
  border: 1px solid var(--mv-rule);
  border-radius: var(--mv-radius);
  padding: 22px 24px;
}
.mv-notice h2,
.mv-notice h3 {
  font-size: 17px;
  font-weight: 800;
  letter-spacing: -0.01em;
  margin-bottom: 8px;
}
.mv-notice p { font-size: 15px; line-height: 1.6; color: var(--mv-soft); }

/* ---------- 10. Note and status boxes ---------- */
.mv-note {
  background: var(--mv-card);
  border-left: 3px solid var(--mv-red);
  border-radius: 0 var(--mv-radius) var(--mv-radius) 0;
  padding: 24px 26px;
}
.mv-note__h {
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: 0 0 10px;
}
.mv-note p { font-size: 16px; line-height: 1.6; color: var(--mv-soft); }
.mv-note__meta {
  margin-top: var(--mv-s2);
  padding-top: 10px;
  border-top: 1px solid var(--mv-rule);
  font-size: 13px;
  color: var(--mv-soft);
}
/* the dated "Where the law stands" box is a note with a stated status */
.mv-status { margin: var(--mv-s4) 0; }

/* ---------- 11. Stats and counts ---------- */
.mv-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--mv-s6);
  margin: 0 0 var(--mv-s5);
}
.mv-stat { margin: 0; }
.mv-stat__figure {
  font-size: clamp(30px, 3.4vw, 40px);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--mv-red-light);
  margin: 0;
}
.mv-band .mv-stat__figure { color: var(--mv-red); }
.mv-band--dark .mv-stat__figure { color: var(--mv-red-light); }
.mv-stat__label {
  margin: 12px 0 0;
  padding-top: 11px;
  border-top: 1px solid var(--mv-rule);
  font-size: 15px;
  line-height: 1.5;
  color: var(--mv-soft);
  max-width: 34ch;
}
.mv-stat__source {
  margin-top: 10px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--mv-soft);
  max-width: 42ch;
}

/* ---------- 12. Lists ---------- */
.mv-dash {
  list-style: none;
  margin: 0 0 var(--mv-s3);
  padding: 0;
}
.mv-dash li {
  position: relative;
  padding: 0 0 0 40px;
  font-size: 17px;
  line-height: 1.55;
}
.mv-dash li + li { margin-top: var(--mv-s3); }
.mv-dash li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 12px;
  width: 22px;
  height: 2px;
  background: var(--mv-red);
}

.mv-beats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--mv-s6);
  counter-reset: mvbeat;
  list-style: none;
  margin: 0;
  padding: 0;
}
.mv-beats > li {
  counter-increment: mvbeat;
  padding-top: var(--mv-s3);
  border-top: 2px solid var(--mv-red);
}
.mv-beats > li::before {
  content: counter(mvbeat);
  display: block;
  font-size: 14px;
  font-weight: 800;
  letter-spacing: 0.1em;
  color: var(--mv-accent);
  margin-bottom: 10px;
}
.mv-beats h3 { margin-bottom: 8px; }
.mv-beats p { font-size: 16px; color: var(--mv-soft); }

/* ---------- 13. Photos and figures ---------- */
.mv-photo {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--mv-charcoal);
  border-radius: var(--mv-radius);
}
.mv-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: sepia(0.16) saturate(1.14) contrast(1.05) brightness(1.02);
}
.mv-photo::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--mv-wash);
  mix-blend-mode: soft-light;
  opacity: 0.16;
  pointer-events: none;
}
.mv-photo--square { border-radius: 0; }
.mv-photo--tall { min-height: 460px; height: 100%; }
.mv-photo--wide { aspect-ratio: 16 / 9; }
.mv-photo--4x3 { aspect-ratio: 4 / 3; }
.mv-figure { margin: 0; }
.mv-figure figcaption,
.mv-photo__caption {
  margin-top: 10px;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--mv-soft);
  max-width: 60ch;
}

/* Pull quote. Used where a slot needs weight but no photograph exists,
   e.g. events we can only describe until the client supplies real images. */
.mv-pullquote {
  display: flex;
  flex-direction: column;
  justify-content: center;
  margin: 0;
  padding: clamp(24px, 3vw, 36px) 0 clamp(24px, 3vw, 36px) clamp(20px, 2.4vw, 30px);
  border-left: 3px solid var(--mv-red);
}
.mv-pullquote__text {
  margin: 0;
  font-size: clamp(21px, 2.3vw, 27px);
  font-weight: 700;
  line-height: 1.32;
  letter-spacing: -0.015em;
  color: var(--mv-ink);
  text-wrap: balance;
}
.mv-pullquote__meta {
  margin: var(--mv-s4) 0 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--mv-soft);
}

/* ---------- 14. Tables ---------- */
.mv-tablewrap {
  overflow-x: auto;
  border: 1px solid var(--mv-rule);
  border-radius: var(--mv-radius);
}
.mv-table {
  width: 100%;
  min-width: 720px;
  border-collapse: collapse;
  font-size: 15px;
  line-height: 1.5;
  background: var(--mv-white);
}
.mv-table th,
.mv-table td {
  padding: 14px 16px;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--mv-rule);
}
.mv-table th {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--mv-soft);
  white-space: nowrap;
}
.mv-table tbody tr:last-child td { border-bottom: 0; }

/* ---------- 15. Forms ---------- */
.mv-form { margin: 0; }
.mv-form__fields { display: grid; gap: var(--mv-s2); }
.mv-form__row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--mv-s2); }
.mv-field { display: block; }
.mv-label {
  display: block;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mv-soft);
  margin-bottom: 6px;
}
.mv-input,
.mv-textarea,
.mv-select {
  width: 100%;
  min-height: 48px;
  padding: 12px 14px;
  background: var(--mv-white);
  color: var(--mv-charcoal);
  border: 1px solid var(--mv-line-sand);
  border-radius: 8px;
  font-size: 16px;
  line-height: 1.4;
  transition: border-color 150ms ease;
}
.mv-textarea { min-height: 120px; resize: vertical; }
.mv-input:hover,
.mv-textarea:hover { border-color: var(--mv-brown); }
.mv-input:focus-visible,
.mv-textarea:focus-visible,
.mv-select:focus-visible { outline: 2px solid var(--mv-focus); outline-offset: 2px; }
.mv-form .mv-btn { margin-top: var(--mv-s2); }
.mv-pdpa {
  margin-top: var(--mv-s2);
  font-size: 13px;
  line-height: 1.55;
  color: var(--mv-soft);
  max-width: 46ch;
}
.mv-form__done {
  padding-top: var(--mv-s1);
  font-size: 16px;
  line-height: 1.6;
  color: var(--mv-ink);
  max-width: 46ch;
}
.mv-form__done strong { color: var(--mv-accent); }

.mv-joincard {
  background: var(--mv-card);
  border-radius: var(--mv-radius);
  padding: 28px 28px 26px;
}
.mv-joincard h2 {
  font-size: 25px;
  letter-spacing: -0.02em;
  margin-bottom: 6px;
}
.mv-joincard > p { font-size: 16px; color: var(--mv-soft); }

/* ---------- 16. Search band and chips ---------- */
.mv-search {
  display: flex;
  flex-wrap: wrap;
  gap: var(--mv-s2);
  align-items: flex-end;
  max-width: 720px;
  margin: 0 0 var(--mv-s2);
}
.mv-search__field { flex: 1 1 320px; }
.mv-search .mv-btn { flex: 0 0 auto; margin-top: 0; }
.mv-search__hint {
  font-size: 13.5px;
  color: var(--mv-soft);
  margin-bottom: var(--mv-s5);
}
.mv-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.mv-chip {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 0 16px;
  border: 1px solid var(--mv-rule);
  border-radius: 999px;
  background: var(--mv-card);
  font-size: 14.5px;
  font-weight: 600;
  color: var(--mv-ink);
  text-decoration: none;
  transition: background-color 150ms ease, border-color 150ms ease, color 150ms ease;
}
.mv-chip:hover { border-color: var(--mv-red-deep); color: var(--mv-red-deep); }

/* ---------- 17. Pathway cards ---------- */
.mv-pathways {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--mv-s4);
}
.mv-pathway {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--mv-card);
  border-radius: var(--mv-radius);
  padding: 24px 24px 22px;
  text-decoration: none;
  color: var(--mv-ink);
  transition: transform 150ms ease, box-shadow 150ms ease;
}
.mv-pathway:hover {
  transform: translateY(-2px);
  box-shadow: 0 1px 2px rgba(42, 39, 36, .08), 0 14px 28px rgba(42, 39, 36, .10);
}
.mv-pathway__title {
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.2;
}
.mv-pathway__desc {
  font-size: 15.5px;
  line-height: 1.55;
  color: var(--mv-soft);
  flex: 1 1 auto;
}
.mv-pathway__go {
  margin-top: 6px;
  font-size: 15px;
  font-weight: 700;
  color: var(--mv-accent);
}

/* ---------- 18. Question cards and Q and A blocks ---------- */
.mv-qcard {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--mv-card);
  border-radius: var(--mv-radius);
  padding: 22px 24px;
}
.mv-qcard h3 { font-size: 19px; line-height: 1.25; margin: 0; }
.mv-qcard h3 a { color: inherit; text-decoration: none; }
.mv-qcard h3 a:hover { color: var(--mv-accent); }
.mv-qcard p { font-size: 15.5px; line-height: 1.55; color: var(--mv-soft); margin: 0; }
.mv-qcard__meta {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mv-soft);
}
.mv-qcard[hidden] { display: none; }

.mv-qa {
  border-top: 1px solid var(--mv-rule);
  padding: var(--mv-s3) 0;
}
.mv-qa > summary {
  cursor: pointer;
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.3;
  list-style: none;
}
.mv-qa > summary::-webkit-details-marker { display: none; }
.mv-qa > summary::after {
  content: "+";
  float: right;
  font-weight: 700;
  color: var(--mv-accent);
  margin-left: var(--mv-s3);
}
.mv-qa[open] > summary::after { content: "\2013"; }
.mv-qa__body { padding-top: var(--mv-s2); max-width: 54ch; }
.mv-searchcount { font-size: 15px; font-weight: 700; color: var(--mv-soft); margin-bottom: var(--mv-s3); }
.mv-searchempty { margin-bottom: var(--mv-s3); }

/* ---------- 19. Reference rail and citation ---------- */
.mv-withrail {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: var(--mv-s6);
  align-items: start;
}
.mv-rail { display: grid; gap: var(--mv-s4); }
.mv-rail__block {
  background: var(--mv-card);
  border-radius: var(--mv-radius);
  padding: 22px 24px;
}
.mv-rail__h {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mv-accent);
  margin: 0 0 var(--mv-s2);
}
.mv-rail__list { list-style: none; margin: 0; padding: 0; font-size: 15px; line-height: 1.5; }
.mv-rail__list li + li { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--mv-rule); }
.mv-cite {
  background: var(--mv-bg);
  border: 1px dashed var(--mv-rule);
  border-radius: 8px;
  padding: 14px 16px;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--mv-ink);
}

/* ---------- 20. MOVE on air panel ---------- */
.mv-air-tab {
  position: fixed;
  right: 0;
  top: 50%;
  z-index: 45;
  transform: translateY(-50%) translateX(0);
  transform-origin: right center;
  writing-mode: vertical-rl;
  padding: 16px 10px;
  background: var(--mv-charcoal);
  color: var(--mv-cream);
  border: 0;
  border-radius: var(--mv-radius) 0 0 var(--mv-radius);
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  cursor: pointer;
  transition: background-color 150ms ease;
}
.mv-air-tab:hover { background: var(--mv-red-deep); }
.mv-air-tab:focus-visible { outline: 2px solid var(--mv-charcoal); outline-offset: 3px; }

.mv-air-backdrop {
  position: fixed;
  inset: 0;
  z-index: 48;
  background: rgba(42, 39, 36, .42);
}
.mv-air-backdrop[hidden] { display: none; }

.mv-air-panel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 50;
  width: min(420px, 92vw);
  overflow-y: auto;
  padding: 28px 26px 40px;
  background: var(--mv-charcoal);
  color: var(--mv-cream);
  --mv-ink: var(--mv-cream);
  --mv-soft: var(--mv-soft-dark);
  --mv-accent: var(--mv-red-light);
  --mv-rule: var(--mv-line-dark);
  --mv-focus: var(--mv-cream);
  box-shadow: -12px 0 40px rgba(42, 39, 36, .28);
  transform: translateX(0);
  transition: transform 200ms ease;
}
.mv-air-panel[hidden] { display: none; }
.mv-air-panel.is-entering { transform: translateX(100%); }
.mv-air-panel h2 {
  font-size: 25px;
  letter-spacing: -0.02em;
  margin-bottom: var(--mv-s3);
}
.mv-air-item {
  padding: var(--mv-s3) 0;
  border-top: 1px solid var(--mv-line-dark);
}
.mv-air-item h3 { font-size: 17px; margin-bottom: 4px; }
.mv-air-item p { font-size: 15px; line-height: 1.55; color: var(--mv-soft-dark); }
.mv-air-item .mv-meta { color: var(--mv-red-light); font-weight: 700; letter-spacing: 0.04em; }
.mv-air-panel__close {
  margin-top: var(--mv-s4);
  min-height: 44px;
  padding: 0 20px;
  background: transparent;
  border: 1.5px solid var(--mv-cream);
  border-radius: 999px;
  color: var(--mv-cream);
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
}
.mv-air-panel__close:hover { background: rgba(250, 246, 239, .10); }

/* ---------- 21. Utilities ---------- */
.mv-vh {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.mv-mt0 { margin-top: 0; }
.mv-mb0 { margin-bottom: 0; }
.mv-mt3 { margin-top: var(--mv-s4); }
.mv-mt4 { margin-top: var(--mv-s5); }
.mv-measure { max-width: 52ch; }
.mv-center { text-align: center; }

/* ============================================================
   22. Reference components (added v1.2, August 2026)
   ------------------------------------------------------------
   The reference pages carry far more sourced material than the
   v1.0 pages did. Density is the risk, so these components buy
   room rather than save it: one idea per block, a hairline
   instead of a box, and generous separation between entries.
   ============================================================ */

/* --- On-page contents. Long reference pages get a map at the top
       so the reader never has to hold the structure in memory. --- */
.mv-toc {
  border-top: 2px solid var(--mv-red);
  padding-top: var(--mv-s3);
  margin: var(--mv-s5) 0 0;
}
.mv-toc__h {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mv-accent);
  margin: 0 0 var(--mv-s2);
}
.mv-toc__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 10px var(--mv-s4);
  list-style: none;
  margin: 0;
  padding: 0;
}
.mv-toc__list a {
  display: block;
  padding: 4px 0;
  font-size: 16px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--mv-ink);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color 150ms ease, border-color 150ms ease;
}
.mv-toc__list a:hover {
  color: var(--mv-accent);
  border-bottom-color: var(--mv-accent);
}

/* --- Source entry. Replaces table rows for the evidence library
       and the coverage register. Each entry is one hairline-separated
       block with room to breathe, and reads top to bottom rather
       than left to right, which is what long citations need. --- */
.mv-sources {
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: mvsrc;
}
.mv-sources > li {
  counter-increment: mvsrc;
  padding: var(--mv-s5) 0;
  border-top: 1px solid var(--mv-rule);
}
.mv-sources > li:first-child { border-top: 2px solid var(--mv-red); }
.mv-sources > li:last-child { padding-bottom: 0; }

.mv-source { display: grid; gap: 10px; max-width: 66ch; }
.mv-source__no {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--mv-soft);
}
.mv-source__no::before { content: counter(mvsrc, decimal-leading-zero); }
.mv-source__title {
  font-size: 21px;
  font-weight: 800;
  line-height: 1.25;
  letter-spacing: -0.02em;
  margin: 0;
  max-width: 46ch;
}
.mv-source__title a { color: inherit; text-decoration-color: var(--mv-red-light); text-underline-offset: 4px; }
.mv-source__title a:hover { color: var(--mv-accent); }
.mv-source__meta {
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--mv-soft);
  margin: 0;
}
.mv-source__body {
  font-size: 16.5px;
  line-height: 1.6;
  margin: 0;
  max-width: 58ch;
}
/* the honest half: what a source does not establish */
.mv-source__limit {
  margin: 0;
  padding-left: var(--mv-s3);
  border-left: 2px solid var(--mv-line-sand);
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--mv-soft);
  max-width: 56ch;
}
.mv-band--sand .mv-source__limit { border-left-color: var(--mv-line); }
.mv-band--dark .mv-source__limit { border-left-color: var(--mv-line-dark); }

/* --- Inline source line. Sits directly under the claim it supports,
       so attribution never costs a trip to the foot of the page. --- */
.mv-src {
  display: block;
  margin: 8px 0 0;
  padding-left: 22px;
  position: relative;
  font-size: 14px;
  line-height: 1.5;
  color: var(--mv-soft);
  max-width: 55ch;
}
.mv-src::before {
  content: "";
  position: absolute;
  left: 0;
  top: 10px;
  width: 14px;
  height: 2px;
  background: var(--mv-red);
}
.mv-src a { color: var(--mv-accent); text-underline-offset: 3px; }

/* --- Tag, for marking an entry's kind or status at a glance. --- */
.mv-tag {
  display: inline-block;
  padding: 3px 10px;
  border: 1px solid var(--mv-rule);
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mv-soft);
  white-space: nowrap;
}
.mv-tag--counter { border-color: var(--mv-red); color: var(--mv-accent); }
.mv-tag--held { border-style: dashed; }
.mv-tags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0;
}

/* --- Argument pair. Used on "the case against us": the criticism
       stated in the critic's own terms, then our answer. Two tones,
       so a reader can never mistake one for the other. --- */
.mv-argument {
  display: grid;
  gap: var(--mv-s4);
  padding: var(--mv-s5) 0;
  border-top: 1px solid var(--mv-rule);
}
.mv-argument:first-of-type { border-top: 2px solid var(--mv-red); }
.mv-argument__claim,
.mv-argument__answer { max-width: 55ch; }
.mv-argument__claim {
  padding-left: var(--mv-s4);
  border-left: 3px solid var(--mv-line-sand);
}
.mv-band--sand .mv-argument__claim { border-left-color: var(--mv-line); }
.mv-argument__answer {
  padding-left: var(--mv-s4);
  border-left: 3px solid var(--mv-red);
}
.mv-argument__who {
  display: block;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mv-soft);
  margin-bottom: 8px;
}
.mv-argument__answer .mv-argument__who { color: var(--mv-accent); }
.mv-argument h3 { font-size: 20px; margin-bottom: 10px; max-width: 40ch; }

/* --- Definition list, for the glossary. --- */
.mv-deflist { margin: 0; }
.mv-deflist > div {
  padding: var(--mv-s4) 0;
  border-top: 1px solid var(--mv-rule);
  max-width: 62ch;
}
.mv-deflist > div:first-child { border-top: 2px solid var(--mv-red); }
.mv-deflist dt {
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.25;
  margin-bottom: 8px;
}
.mv-deflist dd {
  margin: 0;
  font-size: 16.5px;
  line-height: 1.6;
  max-width: 58ch;
}
.mv-deflist dd + dd { margin-top: 8px; }

/* --- Dated timeline, for the law and the movement record. The rule
       runs down the left so a long list still reads as one sequence. --- */
.mv-timeline {
  list-style: none;
  margin: 0;
  padding: 0 0 0 var(--mv-s5);
  border-left: 2px solid var(--mv-rule);
}
.mv-timeline > li {
  position: relative;
  padding: 0 0 var(--mv-s6);
  max-width: 56ch;
}
.mv-timeline > li:last-child { padding-bottom: 0; }
.mv-timeline > li::before {
  content: "";
  position: absolute;
  left: calc(var(--mv-s5) * -1 - 1px);
  top: 9px;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--mv-red);
  transform: translateX(-5px);
}
.mv-timeline__when {
  display: block;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mv-accent);
  margin-bottom: 6px;
}
.mv-timeline h3 { font-size: 20px; margin-bottom: 8px; max-width: 44ch; }
.mv-timeline p { font-size: 16.5px; line-height: 1.6; }
/* a scheduled, not-yet-happened entry reads as hollow */
.mv-timeline > li.is-ahead::before {
  background: var(--mv-bg);
  border: 2px solid var(--mv-red);
}

/* --- Figure block, for the numbers page. Bigger and airier than
       mv-stat, and every figure carries its source. --- */
.mv-figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--mv-s6) var(--mv-s5);
  margin: 0;
  padding: 0;
  list-style: none;
}
.mv-figblock { padding-top: var(--mv-s3); border-top: 2px solid var(--mv-red); }
.mv-figblock__n {
  display: block;
  font-size: clamp(34px, 4vw, 46px);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.03em;
  margin-bottom: 10px;
}
.mv-figblock__what {
  font-size: 16.5px;
  line-height: 1.5;
  margin: 0;
  max-width: 30ch;
}
/* a figure argued by the other side, so it never reads as MOVE's own */
.mv-figblock--counter { border-top-color: var(--mv-brown); }

/* --- Downloadable document. --- */
.mv-doc {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px var(--mv-s2);
  padding: var(--mv-s3) 0;
  border-top: 1px solid var(--mv-rule);
}
.mv-doc:first-of-type { border-top: 2px solid var(--mv-red); }
.mv-doc__title { font-size: 17px; font-weight: 700; line-height: 1.4; margin: 0; }
.mv-doc__meta { font-size: 13.5px; color: var(--mv-soft); margin: 0; }

/* --- Where a page continues elsewhere. --- */
.mv-onward {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--mv-s4);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ---------- 22a. v1.4 hero and card-link updates ---------- */

/* Hero photo cap (D1): keep the whole hero band in view at common viewports. Same
   object-fit: cover as every other photo, just capped so a tall portrait does not push
   the band past the fold. No new image asset. */
.mv-hero__photo {
  align-self: start;
  height: auto;
  min-height: 0;
  max-height: 78vh;
}
.mv-hero__photo img {
  height: auto;
  max-height: 78vh;
  object-fit: cover;
}

/* Whole-card links (D2): the three "What we stand for" position cards on the home page.
   Border and a soft tint on hover/focus stand in for the removed "Read the full position"
   text link. Reuses existing tokens and the same rgba tint already used for ghost-button
   hover states, no new colours. */
.mv-card--link {
  display: block;
  border: 1.5px solid transparent;
  text-decoration: none;
  color: inherit;
  transition: border-color 150ms ease, background-color 150ms ease, transform 150ms ease;
}
.mv-card--link:hover,
.mv-card--link:focus-visible {
  border-color: var(--mv-red);
  background: rgba(42, 39, 36, .05);
  transform: translateY(-2px);
}
.mv-card--link:focus-visible {
  outline: 2px solid var(--mv-focus);
  outline-offset: 3px;
}

/* Sticky header (v1.4.1, Michael 2026-08-20). z-index sits above page content and the
   dropdown menus it contains, below the MOVE-on-air backdrop/panel (48/50) and the skip
   link (60), so the slide-in panel still covers the whole viewport. scroll-margin keeps
   anchor targets (position headings, TOC jumps, #join) clear of the fixed bar. */
.mv-header {
  position: sticky;
  top: 0;
  z-index: 46;
}
[id] {
  scroll-margin-top: 84px;
}

/* ---------- 23. Narrow screens ---------- */
/* the nav carries eight sections now, so it tightens before it wraps */
@media (max-width: 1240px) {
  .mv-nav { gap: var(--mv-s3); }
  .mv-nav__list { gap: 4px 14px; }
  .mv-nav a, .mv-dropdown__trigger { font-size: 14px; }
  .mv-brand__sub { letter-spacing: 0.05em; }
}

@media (max-width: 1040px) {
  .mv-nav__list { gap: 4px 11px; }
  .mv-nav a, .mv-dropdown__trigger { font-size: 13.5px; }
  .mv-brand__sub { display: none; }
  .mv-pathways { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .mv-footer__top { grid-template-columns: minmax(0, 1fr) minmax(0, 2.6fr); }
  .mv-footer__nav { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
  .mv-split,
  .mv-hero__grid { grid-template-columns: minmax(0, 1fr); }
  .mv-hero__photo { min-height: 300px; }
  .mv-cols-2, .mv-cols-3, .mv-cols-4 { grid-template-columns: minmax(0, 1fr); gap: var(--mv-s4); }
  .mv-beats { grid-template-columns: minmax(0, 1fr); gap: var(--mv-s5); }
  .mv-stats { grid-template-columns: minmax(0, 1fr); gap: var(--mv-s5); }
  .mv-withrail { grid-template-columns: minmax(0, 1fr); gap: var(--mv-s5); }
  .mv-photo--tall { min-height: 300px; }
  .mv-footer__top { grid-template-columns: minmax(0, 1fr); gap: var(--mv-s5); }
  .mv-footer__nav { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--mv-s5) var(--mv-s4); }
  .mv-figures { gap: var(--mv-s5) var(--mv-s4); }
}

@media (max-width: 860px) {
  .mv-navtoggle { display: inline-flex; }
  .mv-nav {
    display: none;
    position: relative;
    flex: 1 0 100%;
    flex-direction: column;
    align-items: stretch;
    gap: var(--mv-s3);
    order: 3;
    width: 100%;
    padding: var(--mv-s3) 0 var(--mv-s1);
    border-top: 1px solid var(--mv-line);
  }
  .mv-nav.is-open { display: flex; }
  .mv-header__inner { flex-wrap: wrap; }
  .mv-nav__list { flex-direction: column; align-items: stretch; gap: 0; }
  .mv-nav__list > li + li { border-top: 1px solid var(--mv-line); }
  .mv-nav a, .mv-dropdown__trigger {
    display: block;
    width: 100%;
    padding: 12px 0;
    font-size: 16px;
    text-align: left;
  }
  .mv-nav a[aria-current="page"] { border-bottom: 0; }
  .mv-dropdown__menu {
    position: static;
    min-width: 0;
    margin: 0 0 12px;
    padding: 4px 0 4px 14px;
    border: 0;
    border-left: 2px solid var(--mv-line);
    border-radius: 0;
    box-shadow: none;
    background: transparent;
  }
  .mv-lang { justify-content: flex-start; }
}

@media (max-width: 620px) {
  :root { --mv-pad: 20px; }
  .mv-form__row { grid-template-columns: minmax(0, 1fr); }
  .mv-pathways { grid-template-columns: minmax(0, 1fr); }
  .mv-card, .mv-joincard, .mv-pinned, .mv-note { padding-left: 20px; padding-right: 20px; }
  .mv-air-tab { font-size: 12.5px; padding: 14px 8px; }
  .mv-search .mv-btn { width: 100%; }
  .mv-timeline { padding-left: var(--mv-s4); }
  .mv-timeline > li::before { left: calc(var(--mv-s4) * -1 - 1px); }
  .mv-argument__claim,
  .mv-argument__answer { padding-left: var(--mv-s3); }
  .mv-sources > li { padding: var(--mv-s4) 0; }
}

/* ---------- 24. Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  .mv-btn, .mv-link, .mv-chip, .mv-pathway, .mv-input, .mv-textarea,
  .mv-air-panel, .mv-air-tab, .mv-toc__list a { transition: none; }
  .mv-btn:hover, .mv-btn:active, .mv-pathway:hover { transform: none; }
  .mv-air-panel.is-entering { transform: none; }
  html { scroll-behavior: auto; }
}

/* ---------- 25. Justified body text (added v1.5, client request of 28 Aug 2026) ----------
   Running prose is justified from tablet width up. Phone-width columns are too
   narrow to justify without uneven word spacing, so they stay ragged right.
   Hyphenation keeps the spacing even; it needs the lang="en" attribute the
   pages already carry. Ledes, meta lines, button rows, fineprint, pull quotes
   and form copy keep their ragged setting: short or display-scale text gaps
   badly when justified. Source blocks joined that list on 10 Sep 2026 when they became
   cards: at 13.5px in a narrow figure column, justification opens visible rivers. To put
   them back, delete the main p.mv-src line below. */
@media (min-width: 768px) {
  .mv-band p,
  .mv-band .mv-deflist dd {
    text-align: justify;
    -webkit-hyphens: auto;
    hyphens: auto;
  }
  .mv-band p.mv-lede,
  .mv-band p.mv-meta,
  .mv-band p.mv-btns,
  .mv-band p.mv-fineprint,
  .mv-band p.mv-src,
  .mv-band .mv-src p,
  .mv-band .mv-photo__caption,
  .mv-band .mv-photo__caption p,
  .mv-band figcaption,
  .mv-band figcaption p,
  .mv-band .mv-lede p,
  .mv-band .mv-meta p,
  .mv-band .mv-fineprint p,
  .mv-band .mv-pdpa,
  .mv-band .mv-pdpa p,
  .mv-band .mv-pullquote p,
  .mv-band .elementor-field-group p,
  .mv-band form p {
    text-align: left;
    -webkit-hyphens: none;
    hyphens: none;
  }
}

/* ---------- 26. Announcement bar (added with the events pages; live text from 8 Sep 2026) ----------
   Sitewide slim bar above the header, promised in WIP #5 for event announcements.
   The current text is a sample so the client can see the mechanic; retext or remove
   the .mv-announce block on every page when a real event is confirmed. */
.mv-announce {
  background: var(--mv-charcoal);
  color: var(--mv-cream);
}
.mv-announce__inner {
  max-width: var(--mv-maxw);
  margin: 0 auto;
  padding: 9px var(--mv-pad);
  font-size: 14px;
  line-height: 1.45;
  text-align: center;
}
.mv-announce a {
  color: var(--mv-white);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.mv-announce a:hover,
.mv-announce a:focus-visible { text-decoration-thickness: 2px; }

/* ---------- 27. v1.6 photo variants (added 8 Sep 2026 with the client's archive photographs) ----------
   Real photographs now sit inside timeline cards, the About page and the events column, and two
   documents (a newspaper clipping and an archived petition page) sit in the coverage and position
   pages. These variants keep the existing .mv-photo warm treatment for photographs and switch it
   OFF for documents, which must read as unretouched evidence. No new colours, no new tokens. */
.mv-photo--3x2 { aspect-ratio: 3 / 2; }
.mv-photo--small { max-width: 480px; }
.mv-photo--natural { aspect-ratio: auto; }
.mv-photo--natural img { height: auto; object-fit: contain; }
.mv-photo--document { background: var(--mv-white); border: 1px solid var(--mv-rule); }
.mv-photo--document img { filter: none; }
.mv-photo--document::after { display: none; }
.mv-card .mv-figure { margin-top: var(--mv-s3); }
.mv-card .mv-photo__caption { max-width: none; }

/* ---------- 28. Event cards (added 8 Sep 2026, client request: every listing is one linked card with a featured image) ---------- */
.mv-eventlist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--mv-s3); }
.mv-eventcard {
  display: grid;
  grid-template-columns: 1fr;
  padding: 0;
  overflow: hidden;
  border: 1.5px solid var(--mv-rule);
}
.mv-eventcard__media { border-radius: 0; aspect-ratio: 3 / 2; }
.mv-eventcard__body { padding: 24px 26px 26px; }
.mv-eventcard .mv-card__title { margin-bottom: 10px; }
.mv-eventcard__cta { display: inline-block; margin-top: 16px; font-weight: 700; color: var(--mv-red); }
.mv-eventcard:hover .mv-eventcard__cta,
.mv-eventcard:focus-visible .mv-eventcard__cta { text-decoration: underline; }
@media (min-width: 768px) {
  .mv-eventcard:not(.mv-eventcard--stack) { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
  .mv-eventcard:not(.mv-eventcard--stack) .mv-eventcard__media { aspect-ratio: auto; height: 100%; min-height: 280px; }
}
.mv-eventcard .mv-card__body p { text-align: left; hyphens: manual; }
.mv-eventlist li { padding: 0; margin: 0; list-style: none; }
.mv-eventlist li::before { content: none; display: none; }

/* ---------- 29. Source block as a full-width citation card (client, 10 Sep 2026) ----------
   The 55ch source line sitting under a full-width three-column band read as an orphaned
   half-width column. Giving attribution its own full-width container, detached from the
   content above by a full section gap, says plainly that it is apparatus and not argument.
   The red rule that used to be a 14px dash beside the text is now the card's top edge, so
   the signal is the same one, only louder. The card runs as one column at every width:
   a two-column split was tried on the longest registers and dropped on 10 Sep 2026,
   because a citation is read by hunting for one entry, not by reading it through. */
.mv-src {
  max-width: none;
  margin: var(--mv-s6) 0 0;
  padding: var(--mv-s3) var(--mv-s4) calc(var(--mv-s3) + 2px);
  background: var(--mv-card);
  border: 1px solid var(--mv-rule);
  border-top: 2px solid var(--mv-red);
  border-radius: var(--mv-radius);
  font-size: 13.5px;
  line-height: 1.65;
}
.mv-src::before { display: none; }
/* inside a card the band colour is what contrasts, not the card colour */
.mv-card .mv-src,
.mv-qcard .mv-src,
.mv-figblock .mv-src { background: var(--mv-bg); }
/* a source that follows another source is one apparatus block, not two sections */
.mv-src + .mv-src { margin-top: var(--mv-s2); }

@media (max-width: 640px) {
  .mv-src { margin-top: var(--mv-s5); padding: var(--mv-s3); }
}

/* ---------- 30. Brand logo (client, 10 Sep 2026) ----------
   The header and footer used a type-set wordmark. They now carry the client's own artwork,
   recoloured from MOVE Logo Red Text.jpg into --mv-red-deep and cut out to transparency.
   The strapline stays live text so it keeps its own responsive rule and stays selectable. */
.mv-brand__logo {
  display: block;
  height: 20px;
  width: auto;
}
.mv-brand__logo--footer { height: 24px; }
@media (max-width: 900px) {
  .mv-brand__logo { height: 18px; }
}

/* ---------- 31. Home hero: the Kuala Lumpur drawing (client, 10 September 2026) ----------
   The home page hero drops its photograph column. A line drawing of the city
   runs behind the copy instead, keyed to transparency so the cream of the band
   is the only background there is and the artwork sits directly on it, with no
   box and no edge.

   Anchoring. The drawing is a panorama, 2.357:1, so it is sized by WIDTH and
   laid along the foot of the band. At full width nothing is ever cropped from
   its sides, which is the whole reason it replaced the near square drawing that
   came before it. Merdeka 118 stands between 0.86 and 0.98 across the artwork,
   so at full width the tower lands in the last sixth of the band on its own,
   at every screen size, without being placed there.

   The band is taller than the drawing at ordinary widths, so the artwork sits
   on the floor of it and the copy has clean cream above. Past about 1900px the
   drawing grows taller than the band and loses sky off the top, which is the
   only part of it that can be spared.

   Below 1100 the drawing is scaled past the width of the band and pinned right.
   That crops its left edge, which is ordinary city, and it keeps the tower and
   the foreground at a size worth looking at on a small screen.

   No new colours and no new tokens: the wash, the fade and the ink are all
   built from the cream already in section 2. */
.mv-hero--sketch {
  --mv-draw-w: 100%;          /* the drawing's width, against the band's */
  --mv-wash-end: 72%;         /* where the cream wash reaches nothing */
  --mv-wash-full: 30%;        /* how far it stays solid */

  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  align-items: center;
  min-height: clamp(560px, 72vh, 760px);
  padding-top: clamp(44px, 5vw, 66px);
  padding-bottom: clamp(52px, 6vw, 84px);
}
.mv-hero--sketch > .mv-container {
  position: relative;
  z-index: 2;
  width: 100%;
}
.mv-hero__sketch {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background-image: url("assets/img/kl-line-drawing.webp");
  background-repeat: no-repeat;
  background-position: center bottom;
  background-size: var(--mv-draw-w) auto;
  opacity: .74;
}
/* Legibility. The drawing now runs the full width, so the copy sits over its
   left third. The wash holds solid cream under the copy and lets go before it
   reaches the tower. */
.mv-hero__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(96deg,
      rgba(250, 246, 239, 1) 0%,
      rgba(250, 246, 239, .98) var(--mv-wash-full),
      rgba(250, 246, 239, .6) calc((var(--mv-wash-full) + var(--mv-wash-end)) / 2),
      rgba(250, 246, 239, 0) var(--mv-wash-end));
}
/* the drawing is cut mid-street at its lower edge, so the band edge is softened
   rather than left as a rule across the foreground */
.mv-hero__fade {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  height: 9%;
  pointer-events: none;
  background: linear-gradient(to top, var(--mv-cream) 0%, rgba(250, 246, 239, 0) 100%);
}

/* one column now, so the copy takes a measure of its own instead of a grid track */
.mv-hero--sketch .mv-hero__grid {
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
}
.mv-hero--sketch .mv-hero__copy { max-width: 600px; }
.mv-hero--sketch .mv-hero__copy .mv-display { max-width: 15ch; }
.mv-hero--sketch .mv-hero__copy .mv-lede { max-width: 46ch; }
.mv-hero--sketch .mv-hero__cards { margin-top: var(--mv-s4); }

@media (max-width: 1240px) {
  .mv-hero--sketch { --mv-wash-full: 28%; --mv-wash-end: 68%; }
  .mv-hero--sketch .mv-hero__copy { max-width: 53%; }
}

@media (max-width: 1100px) {
  .mv-hero--sketch { --mv-draw-w: 118%; --mv-wash-full: 24%; --mv-wash-end: 62%; }
  .mv-hero--sketch .mv-hero__copy { max-width: 51%; }
  .mv-hero__sketch { background-position: right bottom; }
}

@media (max-width: 900px) {
  /* The copy runs the full width here, so it has to sit over the drawing. The
     wash turns diagonal for it: solid cream under the heading and the lede at
     the top left, clearing by the foot of the band so the tower and the
     foreground come through behind the button and the notice card. */
  .mv-hero--sketch {
    --mv-draw-w: 140%;
    min-height: clamp(520px, 76vh, 700px);
  }
  .mv-hero--sketch .mv-hero__copy { max-width: none; }
  .mv-hero__sketch {
    background-position: right bottom;
    opacity: .64;
  }
  .mv-hero__veil {
    background: linear-gradient(146deg,
      rgba(250, 246, 239, .99) 0%,
      rgba(250, 246, 239, .96) 36%,
      rgba(250, 246, 239, .55) 66%,
      rgba(250, 246, 239, 0) 90%);
  }
}

@media (max-width: 620px) {
  .mv-hero--sketch { --mv-draw-w: 250%; }
  /* the MOVE on air tab is fixed to the right edge and 36px wide, which on a
     phone clips the last few pixels off the tower. Nudging the drawing in by
     14px clears it and is too small to read as a margin. */
  .mv-hero__sketch {
    background-position: right 14px bottom;
    opacity: .66;
  }
}

/* ---------- 32. Compliance penalties table columns (client, 11 Sep 2026) ---------- */
.mv-table--penalties {
  table-layout: fixed;
  min-width: 720px;
}
.mv-table--penalties th,
.mv-table--penalties td {
  overflow-wrap: break-word;
  word-wrap: break-word;
  white-space: normal;
}

/* ---------- 33. Top utility bar: language and social links (client, 11 Sep 2026) ----------
   Slim bar with one right-aligned group, social links first and the BM|EN language
   switcher at the far right end (client, 11 Sep 2026: v1.7.1 patch), sitting between
   the announcement bar and the main header. Deep red ground
   with everything on it in plain white: white on #B7302A is 6.05:1, which clears AA
   for normal text, so nothing on this bar is tinted below that.
   Bar order on every page, top to bottom: announcement bar, this bar, main header.
   The announcement bar above is to show only while a live notification exists; when
   there is none the .mv-announce block comes out and this bar becomes the top strip.
   The .mv-lang rules in section 6 were written for the cream header, so the
   overrides below are scoped inside .mv-topbar and leave the header untouched. */
.mv-topbar {
  background: var(--mv-red-deep);
  color: var(--mv-white);
}
.mv-topbar__inner {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 20px;
  min-height: 38px;
  flex-wrap: nowrap;
}
.mv-topbar .mv-lang {
  gap: 4px;
  color: var(--mv-white);
  flex: 0 0 auto;
}
.mv-topbar .mv-lang__btn {
  color: var(--mv-white);
  padding: 4px 2px;
}
.mv-topbar .mv-lang__btn[disabled] { opacity: .8; }
.mv-topbar .mv-lang__btn.is-active {
  color: var(--mv-white);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.mv-social {
  display: flex;
  align-items: center;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
  flex: 0 0 auto;
}
.mv-social__link {
  display: block;
  padding: 6px;
  color: var(--mv-white);
  text-decoration: none;
}
.mv-social__icon {
  display: block;
  width: 18px;
  height: 18px;
  fill: currentColor;
}
.mv-social__link:hover { opacity: .75; }
.mv-topbar a:focus-visible,
.mv-topbar button:focus-visible {
  outline: 2px solid var(--mv-white);
  outline-offset: 2px;
}

@media (max-width: 480px) {
  .mv-social__link { padding: 5px; }
  .mv-social__icon { width: 16px; height: 16px; }
}

@media print {
  .mv-topbar { display: none; }
}

/* ---------- 34. Share row (client, 11 Sep 2026) ----------
   Quiet apparatus at the foot of the reference pages: a small label and four
   compact controls, on the page ground with one hairline above so the row reads
   as a tool bar and not as a call to action. Charcoal text and icons, red kept
   for hover and focus per the site's link discipline. Four controls only:
   WhatsApp, Facebook, X and the native share button, which stays hidden in the
   markup until site.js module 7 finds navigator.share. There is no copy-link
   control, by client decision. The row wraps rather than scrolls, so it holds at
   375px with nothing over the edge. */
.mv-sharebar {
  background: var(--mv-bg);
  color: var(--mv-ink);
  border-top: 1px solid var(--mv-line);
  padding: var(--mv-s6) 0;
}
.mv-sharebar__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--mv-s2) var(--mv-s4);
}
.mv-sharebar__label {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.3;
  color: var(--mv-charcoal);
}
.mv-share {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--mv-s1);
  margin: 0;
  padding: 0;
  list-style: none;
}
.mv-share__btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  background: transparent;
  border: 1px solid rgba(42, 39, 36, .25);
  border-radius: var(--mv-radius);
  color: var(--mv-charcoal);
  font-family: var(--mv-font);
  font-size: 14px;
  font-weight: 700;
  line-height: 1.2;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: border-color 150ms ease, color 150ms ease, background-color 150ms ease;
}
.mv-share__btn[hidden] { display: none; }
.mv-share__btn:hover {
  border-color: var(--mv-red-deep);
  color: var(--mv-red-deep);
  background: rgba(42, 39, 36, .04);
}
.mv-share__btn:focus-visible {
  outline: 2px solid var(--mv-focus);
  outline-offset: 2px;
}
.mv-share__icon {
  display: block;
  width: 17px;
  height: 17px;
  fill: currentColor;
  flex: 0 0 auto;
}

@media (max-width: 560px) {
  .mv-sharebar { padding: var(--mv-s5) 0; }
  .mv-share { gap: 6px; }
  .mv-share__btn { padding: 7px 11px; }
}

@media print {
  .mv-sharebar { display: none; }
}

/* ---------- 35. Get involved hero: the Merdeka 118 drawing (client, 11 September 2026) ----------
   A second line drawing from the client, in the same hand as the home page one,
   and given the same treatment: keyed to transparency, re-inked in the same
   warm dark brown, and sat straight on the cream of the band with no box and no
   edge. Section 31 is the home hero and is not touched by any of this.

   Anchoring. This artwork is tower dominant and roughly square, 0.840:1, with
   Merdeka 118 centred and its spire at the very top of the frame. Sized by
   WIDTH it would either tower over the band or shrink to nothing, so it is
   sized by HEIGHT instead and pinned RIGHT. That keeps the whole tower on
   screen at every width, keeps the drawing clear of the copy at the left, and
   makes the flanking towers and the island base the part that leaves the frame
   first if anything has to.

   It is held a little off the foot of the band as well, because the base of the
   drawing is a floating island with a ragged underside: standing it on the band
   edge would read as a crop, and letting it float is what the artwork is.

   Legibility. The wash is diagonal, like the narrow screen treatment in section
   31: solid cream under the kicker, the heading and the lede at the left, and
   gone before it reaches the tower.

   No new colours and no new tokens. The cream in the gradient stops is the
   #FAF6EF of section 2, written out because a gradient stop needs its own
   alpha.

   Right edge, 12 September 2026 (client): on wide screens the layers used to
   run to the VIEWPORT's right edge (inset: 0 on the section, which spans full
   bleed). The client asked for the drawing to stop at the CONTENT COLUMN's
   right edge instead, the same 1140px .mv-container the text uses.

   --mv-gi-edge is that gutter, in one place: half the gap between the section
   (full viewport width, since .mv-band carries no side padding) and the
   1140px container, floored at 0. It is a PERCENTAGE calc, not vw: percentage
   values on an absolutely positioned element's offsets resolve against the
   actual rendered width of the containing block (the section, which is a real
   block box, not the initial containing block), so it already excludes the
   scrollbar. calc(100vw - 1140px) would not: vw is fixed to the initial
   containing block regardless of whether a scrollbar is actually stealing
   width, so it drifts by the scrollbar's own width wherever one is present.
   Below 1140px wide the calc goes negative and max() floors it at 0, which is
   exactly today's edge-to-edge behaviour, so nothing below that point moves. */
.mv-hero--gi {
  --mv-gi-h: 88%;             /* the drawing's height, against the band's */
  --mv-gi-lift: 6%;           /* how far the island floats off the band edge */
  --mv-gi-inset: 0px;         /* room for the MOVE on air tab, phones only */
  --mv-gi-wash-full: 44%;     /* how far the cream stays solid */
  --mv-gi-wash-end: 78%;      /* where it reaches nothing */
  --mv-gi-edge: max(0px, calc((100% - var(--mv-maxw)) / 2)); /* container's right gutter */

  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  align-items: center;
  min-height: 560px;
  padding-bottom: clamp(48px, 5vw, 72px);
}
.mv-hero--gi > .mv-container {
  position: relative;
  z-index: 2;
  width: 100%;
}
.mv-hero__drawing {
  position: absolute;
  top: 0;
  right: var(--mv-gi-edge);
  bottom: 0;
  left: 0;
  z-index: 0;
  overflow: hidden;
  background-image: url("assets/img/gi-kl-merdeka.webp");
  background-repeat: no-repeat;
  background-position: right var(--mv-gi-inset) bottom var(--mv-gi-lift);
  background-size: auto var(--mv-gi-h);
  opacity: .74;
}
.mv-hero__wash {
  position: absolute;
  top: 0;
  right: var(--mv-gi-edge);
  bottom: 0;
  left: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(100deg,
      rgba(250, 246, 239, 1) 0%,
      rgba(250, 246, 239, .98) var(--mv-gi-wash-full),
      rgba(250, 246, 239, .58) calc((var(--mv-gi-wash-full) + var(--mv-gi-wash-end)) / 2),
      rgba(250, 246, 239, 0) var(--mv-gi-wash-end));
}
.mv-hero--gi .mv-display { max-width: 17ch; }
.mv-hero--gi .mv-lede { max-width: 46ch; }

@media (max-width: 1100px) {
  .mv-hero--gi {
    --mv-gi-wash-full: 40%;
    --mv-gi-wash-end: 74%;
    min-height: 520px;
  }
}

/* The copy runs the full width below this, so it sits over the drawing and the
   wash turns diagonal for it, as the home hero's does. The drawing stays a
   background at every width and is never dropped below the copy. */
@media (max-width: 900px) {
  .mv-hero--gi {
    --mv-gi-h: 84%;
    --mv-gi-lift: 4%;
    min-height: clamp(480px, 72vh, 560px);
  }
  .mv-hero__drawing { opacity: .64; }
  .mv-hero__wash {
    background: linear-gradient(152deg,
      rgba(250, 246, 239, .99) 0%,
      rgba(250, 246, 239, .96) 38%,
      rgba(250, 246, 239, .55) 68%,
      rgba(250, 246, 239, 0) 92%);
  }
}

@media (max-width: 620px) {
  /* the MOVE on air tab is fixed to the right edge and 36px wide, which on a
     phone clips the last few pixels off the spire. Nudging the drawing in by
     14px clears it and is too small to read as a margin. */
  .mv-hero--gi {
    --mv-gi-h: 80%;
    --mv-gi-inset: 14px;
  }
}

/* ---------- 36. Sample bottle diagram (client, 12 September 2026) ----------
   The six-things block on the consumer guide is one generated diagram: a
   sample bottle with the six required label items called out on it. It
   replaced the two-column panel built earlier the same day, which paired the
   same bottle with a visible numbered list beside it, so most of this section
   went with that layout. What is gone: the .mv-bottle grid and its 900px
   two-column rule, and the .mv-bottle__points list with its charcoal counter
   discs and their print override. Nothing else in the stylesheet referenced
   any of it.

   The six item strings are still in the page, as a visually hidden list
   directly under the figure, because the words are the content: screen
   readers, site search and the Bahasa Malaysia edition all need them, and a
   diagram cannot carry any of that.

   The figure needs no frame and no plate. Its ground was white balanced to
   --mv-cream before export, which is the fill of the card it sits in
   (.mv-card inside .mv-band--sand re-points --mv-card to --mv-cream), so the
   figure meets the card with no visible edge. That is also why it does not
   use .mv-photo: that class carries a warm filter and a soft-light wash meant
   for photographs, and either one would pull the ground back out of register.

   Spacing is deliberately NOT set here. Section 27 already carries
   .mv-card .mv-figure { margin-top: var(--mv-s3) }, which outranks a single
   class anyway, so a margin rule on .mv-bottle__figure would have been dead
   code. The figure keeps the card's own rhythm, which is what it should do.

   No new colours and no new tokens.

   Patch, 12 September 2026 (client: halve the display height). Measured over
   http before this patch, the image rendered at 1038 by 696px at a 1280px
   viewport, card width driving it because the rule above was a bare
   width: 100%. Capping the image at max-width: 519px (half the measured
   1038px, rounded to the nearest px) halves the rendered height too, since
   width and height attributes on the img already fix its aspect ratio at
   2200 by 1476. margin-inline: auto and display: block recentre the now
   narrower image inside the card; the figure and card keep their existing
   padding untouched. Below the 519px cap, on phones where the card itself is
   narrower than that, width: 100% still governs and nothing changes: at a
   375px viewport the image measured 293 by 197px before this patch and
   measures the same after it. The asset itself, bottle-six-things.webp, is
   not touched. */
.mv-bottle__figure img {
  width: 100%;
  max-width: 519px;
  margin-inline: auto;
  display: block;
}

/* ---------- 37. Act 852 retailer guide figure (client, 12 September 2026) ----------
   The quick-reference guide at the top of "The rules at a glance" on the
   retailer page. It is a summary of the two cards below it, so it sits full
   width in the container between the lede and the cards, and it is spaced to
   read as its own step: 32px above, 48px below, which is the gap the cards
   themselves use.

   The client asked for the infographic on a white background, so the artwork's
   ground is exported at #FFFFFF and the page gives it a plate to sit on. The
   plate is NOT a new component: the markup puts .mv-card and .mv-card--line on
   the wrapper, so it takes the same hairline, the same radius and the same
   box as the two cards below it, and the only thing overridden here is the
   fill. Without that the white artwork would be a bare rectangle on the sand
   band, which is the "pasted on" look. Padding is squared off at 24px because
   the card's own 26/26/24 is tuned for text with descender space under it, and
   an image wants an even margin on all four sides.

   The fill is --mv-white, not --mv-card. In a .mv-band--sand section --mv-card
   resolves to --mv-cream, and cream behind a pure white image would show the
   artwork as a lighter rectangle inside its own plate. So the plate matches
   the artwork exactly and the difference in tone from the cream cards below is
   deliberate: this is a figure, they are text.

   The caption stays OUTSIDE the plate, on the band, because it is apparatus
   about the figure rather than part of it. That is why .mv-card sits on an
   inner wrapper and not on the <figure> itself.

   The image scales with the container and never exceeds it: the base rule in
   section 3 already sets max-width 100% and height auto on every img, and
   width 100% here makes that explicit rather than incidental. The guide's own
   text is small at phone widths, which is why the alt text and the caption
   both send the reader to the full rules in the text below.

   No new colours and no new tokens: --mv-white is already in section 2. */
.mv-guide {
  margin: var(--mv-s5) 0 var(--mv-s6);
}
.mv-guide__plate {
  background: var(--mv-white);
  padding: var(--mv-s4);
}
.mv-guide img {
  width: 100%;
}

/* On a phone the container is already narrow and the guide's own text is the
   first thing that suffers, so the plate gives most of its padding back:
   measured at 375, 24px of padding took the artwork from 335px to 285px, a
   seventh of its width, for a margin nobody reads. 620 is the breakpoint the
   rest of the stylesheet uses for this. */
@media (max-width: 620px) {
  .mv-guide__plate { padding: var(--mv-s2); }
}

/* ============================================================
   38. Elementor glue (WordPress port, 14 September 2026)
   ------------------------------------------------------------
   Everything in this section exists only because the page is
   assembled in Elementor instead of hand written HTML. Nothing
   here changes the design. It does three jobs:

     a. it re-points the structural rules above at the DOM
        Elementor actually emits,
     b. it neutralises the Elementor kit's own type and colour
        defaults, which would otherwise paint every heading deep
        red and pin every heading to the h2 size whatever tag it
        carries, and
     c. it pushes the mv- classes that a page worker puts on a
        WIDGET WRAPPER down onto the element Elementor renders
        inside that wrapper.

   The DOM below was observed on this install, not assumed. The
   captured render is in .foreman/scratch/wp-build/dom-probe.html
   (page 38, "_dev-css-probe", left in draft on purpose).

   Elementor 4.2.4 emits:

     full container   <section class="elementor-element e-con-full
                        MV-CLASSES e-flex e-con">
     boxed container  <div class="elementor-element e-con-boxed
                        MV-CLASSES e-con"><div class="e-con-inner">
     widget           <div class="elementor-element MV-CLASSES
                        elementor-widget elementor-widget-TYPE">

   There is NO .elementor-widget-container in this version. The
   widget's own markup is a DIRECT CHILD of the widget div:

     heading   ->  <h1..h6|p|span class="elementor-heading-title">
     text      ->  the authored HTML, unwrapped
     image     ->  a bare <img> when the caption source is none,
                   <figure class="wp-caption"> when it is custom
     button    ->  <a class="elementor-button">
     form      ->  <form class="elementor-form">

   The child stylesheet is enqueued last of all (verified: the
   style queue ends hello-elementor-child-style, after
   elementor-post-8), so equal specificity resolves this way.
   Even so, every rule that has to beat a kit rule below is
   written one class heavier than the rule it beats, so the port
   does not depend on that order holding.
   ============================================================ */

/* --- a1. Bands ----------------------------------------------
   A band is a full width container. Elementor writes its own
   padding longhands on .e-con, so the band padding is restated
   here one class heavier. Band padding is owned by this
   stylesheet and never by the Elementor padding control. */
.e-con.mv-band {
  padding-block: clamp(48px, 6vw, 80px);
  padding-inline: 0;
}
.e-con.mv-band--slim { padding-block: clamp(40px, 4.4vw, 56px); }
.e-con.mv-hero { padding-block-start: clamp(40px, 4.6vw, 60px); }
.e-con.mv-hero--sketch {
  padding-block-start: clamp(44px, 5vw, 66px);
  padding-block-end: clamp(52px, 6vw, 84px);
}
.e-con.mv-hero--gi { padding-block-end: clamp(48px, 5vw, 72px); }
.e-con.mv-sharebar { padding-block: var(--mv-s6); padding-inline: 0; }
@media (max-width: 560px) {
  .e-con.mv-sharebar { padding-block: var(--mv-s5); }
}

/* --- a2. The boxed container inside a band -------------------
   This is the old .mv-container. 1140px including a 24px gutter
   on each side gives the same 1092px measure the static site
   had. It is set here rather than left to the Elementor control
   because the builder only writes --content-width inside a
   min-width: 768px query, so below that width the gutter would
   otherwise disappear and the text would touch the screen edge.
   Page workers still set the boxed width to 1140 in the panel so
   the editor canvas matches, but this rule is what governs. */
.mv-bandinner > .e-con-inner {
  width: 100%;
  max-width: var(--mv-maxw);
  margin-inline: auto;
  padding-inline: var(--mv-pad);
}

/* --- a3. Grid components on containers -----------------------
   These components keep their own display and their own gap. The
   stacking breakpoints in section 23 are part of the design and
   must not be handed to the builder's 1024 / 767 pair. Do not
   set a flex gap on a container carrying one of these classes:
   the value below wins and the panel setting will read as a lie. */
.e-con.mv-cols-2,
.e-con.mv-cols-3,
.e-con.mv-cols-4,
.e-con.mv-split,
.e-con.mv-stats,
.e-con.mv-pathways,
.e-con.mv-figures,
.e-con.mv-withrail,
.e-con.mv-beats,
.e-con.mv-hero__grid,
.e-con.mv-hero__cards,
.e-con.mv-rail,
.e-con.mv-footer__top,
.e-con.mv-footer__nav,
.e-con.mv-onward,
.e-con.mv-form__fields,
.e-con.mv-form__row { display: grid; }
.e-con.mv-cols-2 { gap: var(--mv-s6); }
.e-con.mv-cols-3,
.e-con.mv-cols-4 { gap: var(--mv-s4); }
.e-con.mv-split { gap: 0; }
.e-con.mv-split--gap { gap: clamp(32px, 4vw, 56px); }
.e-con.mv-sechead,
.e-con.mv-btns,
.e-con.mv-search,
.e-con.mv-tags,
.e-con.mv-sharebar__inner,
.e-con.mv-header__inner,
.e-con.mv-topbar__inner { display: flex; }
@media (max-width: 900px) {
  .e-con.mv-cols-2,
  .e-con.mv-cols-3,
  .e-con.mv-cols-4 { gap: var(--mv-s4); }
}

/* --- a4. Boxed components on containers ----------------------
   Same reason as the band padding: Elementor writes padding
   longhands on every .e-con, so a component that is a box has to
   restate its padding one class heavier. */
.e-con.mv-card { padding: 26px 26px 24px; }
.e-con.mv-notice { padding: 22px 24px; }
.e-con.mv-note { padding: 24px 26px; }
.e-con.mv-joincard { padding: 28px 28px 26px; }
.e-con.mv-pinned { padding: 30px 32px; }
.e-con.mv-qcard { padding: 22px 24px; }
.e-con.mv-rail__block { padding: 22px 24px; }
.e-con.mv-guide__plate { padding: var(--mv-s4); }
.e-con.mv-eventcard { padding: 0; }
.e-con.mv-eventcard__body { padding: 24px 26px 26px; }
.e-con.mv-air-panel { padding: 28px 26px 40px; }
@media (max-width: 620px) {
  .e-con.mv-card,
  .e-con.mv-joincard,
  .e-con.mv-pinned,
  .e-con.mv-note { padding-left: 20px; padding-right: 20px; }
  .e-con.mv-guide__plate { padding: var(--mv-s2); }
}

/* --- a5. The two illustrated heroes --------------------------
   The band centres its copy instead of shrinking to it: the
   builder lays a container out as a flex column, so vertical
   centring is justify-content and full width is align-items. */
.e-con.mv-hero--sketch,
.e-con.mv-hero--gi {
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
}
/* The decorative layers are absolutely positioned against the
   band. Elementor gives every widget position: relative, which
   would make them position against the widget instead, so the
   one HTML widget that carries them is put back to static. It
   must be a DIRECT child of the band container, not of the boxed
   inner one, or inset: 0 will cover the wrong box. */
.elementor-widget.mv-herolayers { position: static; }

/* --- b1. Heading widgets ------------------------------------
   The kit paints every heading widget with the primary global
   colour, which is the deep red, and with the primary global
   typography, which is the h2 setting, whatever tag the heading
   carries. Both are undone here so the cascade in sections 3 and
   4 governs again and a dark band's tone still reaches the type
   inside it. */
.elementor-element.elementor-widget-heading > .elementor-heading-title {
  font-family: var(--mv-font);
  color: inherit;
  margin: 0;
}
.elementor-element.elementor-widget-heading > h1.elementor-heading-title {
  font-size: clamp(38px, 5.4vw, 58px);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.03em;
}
.elementor-element.elementor-widget-heading > h2.elementor-heading-title {
  font-size: clamp(28px, 3.6vw, 40px);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.03em;
}
.elementor-element.elementor-widget-heading > h3.elementor-heading-title,
.elementor-element.elementor-widget-heading > h4.elementor-heading-title,
.elementor-element.elementor-widget-heading > h5.elementor-heading-title,
.elementor-element.elementor-widget-heading > h6.elementor-heading-title {
  font-size: 22px;
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -0.02em;
}
.elementor-element.elementor-widget-heading > p.elementor-heading-title,
.elementor-element.elementor-widget-heading > span.elementor-heading-title,
.elementor-element.elementor-widget-heading > div.elementor-heading-title {
  font-size: 17px;
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: normal;
}

/* --- b2. Component classes on a heading widget ---------------
   A heading widget that carries one of the classes below hands
   its own computed type to the tag inside it, so the class works
   exactly as it does in the static markup. The list is explicit
   on purpose: a blanket [class*="mv-"] would also catch a
   heading carrying nothing but a spacing utility and strip its
   size. A class that is NOT on this list must not be used on a
   heading widget to set type; put it on the markup instead. */
.elementor-widget-heading.mv-display > .elementor-heading-title,
.elementor-widget-heading.mv-display--sm > .elementor-heading-title,
.elementor-widget-heading.mv-h2 > .elementor-heading-title,
.elementor-widget-heading.mv-kicker > .elementor-heading-title,
.elementor-widget-heading.mv-lede > .elementor-heading-title,
.elementor-widget-heading.mv-lede--sm > .elementor-heading-title,
.elementor-widget-heading.mv-meta > .elementor-heading-title,
.elementor-widget-heading.mv-body > .elementor-heading-title,
.elementor-widget-heading.mv-fineprint > .elementor-heading-title,
.elementor-widget-heading.mv-label > .elementor-heading-title,
.elementor-widget-heading.mv-flag > .elementor-heading-title,
.elementor-widget-heading.mv-tag > .elementor-heading-title,
.elementor-widget-heading.mv-card__kicker > .elementor-heading-title,
.elementor-widget-heading.mv-card__title > .elementor-heading-title,
.elementor-widget-heading.mv-note__h > .elementor-heading-title,
.elementor-widget-heading.mv-source__no > .elementor-heading-title,
.elementor-widget-heading.mv-source__title > .elementor-heading-title,
.elementor-widget-heading.mv-source__meta > .elementor-heading-title,
.elementor-widget-heading.mv-timeline__when > .elementor-heading-title,
.elementor-widget-heading.mv-toc__h > .elementor-heading-title,
.elementor-widget-heading.mv-rail__h > .elementor-heading-title,
.elementor-widget-heading.mv-argument__who > .elementor-heading-title,
.elementor-widget-heading.mv-figblock__n > .elementor-heading-title,
.elementor-widget-heading.mv-figblock__what > .elementor-heading-title,
.elementor-widget-heading.mv-footer__h > .elementor-heading-title,
.elementor-widget-heading.mv-pathway__title > .elementor-heading-title,
.elementor-widget-heading.mv-pathway__desc > .elementor-heading-title,
.elementor-widget-heading.mv-pathway__go > .elementor-heading-title,
.elementor-widget-heading.mv-qcard__meta > .elementor-heading-title,
.elementor-widget-heading.mv-stat__figure > .elementor-heading-title,
.elementor-widget-heading.mv-stat__label > .elementor-heading-title,
.elementor-widget-heading.mv-stat__source > .elementor-heading-title,
.elementor-widget-heading.mv-doc__title > .elementor-heading-title,
.elementor-widget-heading.mv-doc__meta > .elementor-heading-title,
.elementor-widget-heading.mv-pullquote__text > .elementor-heading-title,
.elementor-widget-heading.mv-pullquote__meta > .elementor-heading-title,
.elementor-widget-heading.mv-sharebar__label > .elementor-heading-title,
.elementor-widget-heading.mv-searchcount > .elementor-heading-title,
.elementor-widget-heading.mv-search__hint > .elementor-heading-title,
.elementor-widget-heading.mv-announce__inner > .elementor-heading-title,
.elementor-widget-heading.mv-footer__line > .elementor-heading-title,
.elementor-widget-heading.mv-footer__notice > .elementor-heading-title,
.elementor-widget-heading.mv-footer__meta > .elementor-heading-title,
.elementor-widget-heading.mv-wordmark > .elementor-heading-title,
.elementor-widget-heading.mv-brand__sub > .elementor-heading-title,
.elementor-widget-heading.mv-pdpa > .elementor-heading-title {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  word-spacing: inherit;
  text-transform: inherit;
  text-align: inherit;
  margin: 0;
}

/* --- b3. Text editor widgets --------------------------------
   The kit pins the text editor to the text global colour, which
   breaks the dark band, and to the text global type. The widget
   wrapper is put back to a plain, transparent box. This is safe
   ONLY because of the contract rule that a text editor widget
   carries the static markup VERBATIM inside it, classes and all,
   and carries nothing but spacing utilities on the wrapper. A
   typographic class on the wrapper would be beaten by this rule. */
.elementor-element.elementor-widget-text-editor {
  font-family: var(--mv-font);
  font-size: 17px;
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: normal;
  word-spacing: normal;
  color: inherit;
}
.elementor-element.elementor-widget-text-editor > :last-child { margin-bottom: 0; }
.elementor-element.elementor-widget-html { color: inherit; }

/* --- b4. Image widgets --------------------------------------
   With the caption source set to none, the <img> is the widget
   div's only child, so a widget carrying mv-photo behaves
   exactly as the static <div class="mv-photo"> it replaces and
   needs no rule at all. The rules below only cover the case
   where Elementor's own caption is used, which the contract
   allows for unframed figures and forbids for mv-photo. */
.elementor-element.elementor-widget-image figure.wp-caption { margin: 0; }
.elementor-element.elementor-widget-image .widget-image-caption {
  font-family: var(--mv-font);
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--mv-soft);
  text-align: left;
  margin-top: 10px;
}
.elementor-widget-image.mv-photo > img { width: 100%; height: 100%; }

/* --- b5. Button widgets -------------------------------------
   The mv-btn classes ride the widget wrapper, because that is
   the only place Elementor will put a custom class. The pill
   itself is the <a class="elementor-button"> inside it, so the
   wrapper is stripped back and the look is restated on the
   anchor. The declarations are the same ones as section 8. */
.elementor-widget-button.mv-btn {
  display: block;
  width: auto;
  min-height: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  transform: none;
  transition: none;
}
.elementor-widget-button.mv-btn > .elementor-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 0 26px;
  border: 1.5px solid transparent;
  border-radius: 999px;
  background: none;
  color: inherit;
  font-family: var(--mv-font);
  font-size: 16px;
  font-weight: 700;
  line-height: 1;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 150ms ease, border-color 150ms ease,
              color 150ms ease, transform 150ms ease;
}
.elementor-widget-button.mv-btn--primary > .elementor-button {
  background: var(--mv-red);
  color: var(--mv-white);
  box-shadow: 0 1px 2px rgba(42, 39, 36, .10), 0 8px 18px rgba(42, 39, 36, .10);
}
.elementor-widget-button.mv-btn--primary > .elementor-button:hover {
  background: var(--mv-red-deep);
  transform: translateY(-1px);
}
.elementor-widget-button.mv-btn--primary > .elementor-button:active {
  transform: translateY(0) scale(.99);
}
.elementor-widget-button.mv-btn--ghost > .elementor-button {
  background: transparent;
  border-color: var(--mv-ink);
  color: var(--mv-ink);
}
.elementor-widget-button.mv-btn--ghost > .elementor-button:hover {
  background: rgba(42, 39, 36, .06);
  transform: translateY(-1px);
}
.mv-band--dark .elementor-widget-button.mv-btn--ghost > .elementor-button:hover {
  background: rgba(250, 246, 239, .10);
}
.elementor-widget-button.mv-btn--ghost > .elementor-button:active {
  transform: translateY(0) scale(.99);
}
.elementor-widget-button.mv-btn > .elementor-button:focus-visible {
  outline: 2px solid var(--mv-focus);
  outline-offset: 3px;
}

/* --- b6. Elementor Pro form widget --------------------------
   The form widget carries mv-form on its wrapper. Everything
   inside is Elementor's own markup, so the field, label and
   submit styles from section 15 are restated against it. Each
   rule is written one class heavier than the Pro and kit rules
   it has to beat. */
.mv-form .elementor-form { margin: 0; }
.mv-form .elementor-form-fields-wrapper {
  display: grid;
  gap: var(--mv-s2);
  margin: 0;
}
.mv-form .elementor-form-fields-wrapper > .elementor-field-group {
  display: block;
  width: 100%;
  max-width: none;
  flex: none;
  padding: 0;
  margin: 0;
}
.mv-form .elementor-field-group > .elementor-field-label {
  display: block;
  padding: 0;
  margin-bottom: 6px;
  font-family: var(--mv-font);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--mv-soft);
}
.mv-form .elementor-field-group .elementor-field-textual {
  width: 100%;
  min-height: 48px;
  padding: 12px 14px;
  background: var(--mv-white);
  color: var(--mv-charcoal);
  border: 1px solid var(--mv-line-sand);
  border-radius: 8px;
  box-shadow: none;
  font-family: var(--mv-font);
  font-size: 16px;
  line-height: 1.4;
  transition: border-color 150ms ease;
}
.mv-form .elementor-field-group textarea.elementor-field-textual {
  min-height: 120px;
  resize: vertical;
}
.mv-form .elementor-field-group .elementor-field-textual:hover {
  border-color: var(--mv-brown);
}
.mv-form .elementor-field-group .elementor-field-textual:focus,
.mv-form .elementor-field-group .elementor-field-textual:focus-visible {
  border-color: var(--mv-brown);
  outline: 2px solid var(--mv-focus);
  outline-offset: 2px;
}
.mv-form .elementor-form-fields-wrapper > .e-form__buttons {
  display: block;
  margin-top: var(--mv-s2);
  padding: 0;
}
.mv-form .e-form__buttons .elementor-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: auto;
  min-height: 48px;
  padding: 0 26px;
  border: 1.5px solid transparent;
  border-radius: 999px;
  background: var(--mv-red);
  color: var(--mv-white);
  box-shadow: 0 1px 2px rgba(42, 39, 36, .10), 0 8px 18px rgba(42, 39, 36, .10);
  font-family: var(--mv-font);
  font-size: 16px;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 150ms ease, transform 150ms ease;
}
.mv-form .e-form__buttons .elementor-button:hover {
  background: var(--mv-red-deep);
  transform: translateY(-1px);
}
.mv-form .e-form__buttons .elementor-button:focus-visible {
  outline: 2px solid var(--mv-focus);
  outline-offset: 3px;
}
.mv-form .elementor-message { font-size: 15px; line-height: 1.6; }

@media (prefers-reduced-motion: reduce) {
  .elementor-widget-button.mv-btn > .elementor-button,
  .mv-form .elementor-field-group .elementor-field-textual,
  .mv-form .e-form__buttons .elementor-button { transition: none; }
  .elementor-widget-button.mv-btn > .elementor-button:hover,
  .elementor-widget-button.mv-btn > .elementor-button:active,
  .mv-form .e-form__buttons .elementor-button:hover { transform: none; }
}

/* --- c. Housekeeping ----------------------------------------
   Elementor's own entrance animations are not used anywhere in
   this design. Motion is CSS only and already switches off under
   prefers-reduced-motion in section 24. */
.e-con > .elementor-widget > :last-child { margin-bottom: 0; }

/* ============================================================
   39. Elementor nav widget adaptation (14 September 2026)
   ------------------------------------------------------------
   Source: .foreman/scratch/wp-build/header-nav-glue.css, part
   d2, written by the theme builder ticket and merged here on the
   lead's wave 1 adjudication.

   Section 6 above was written for the static markup:

     nav.mv-nav > ul.mv-nav__list > li.mv-dropdown
       > button.mv-dropdown__trigger
       > ul.mv-dropdown__menu > li > a

   The header template uses Elementor's WordPress Menu widget,
   which emits, inside a widget div carrying mv-nav:

     nav.elementor-nav-menu--main > ul.elementor-nav-menu
       > li.menu-item.menu-item-has-children
         > a.elementor-item (+ span.sub-arrow)
         > ul.sub-menu.elementor-nav-menu--dropdown
           > li > a.elementor-sub-item

   Only .mv-nav itself and the loose `.mv-nav a` rule survive
   that change, and `.mv-nav a` (0,1,1) loses to Elementor's own
   `.elementor-nav-menu--main .elementor-item` (0,2,0). Without
   this section the navigation renders as a stock Elementor menu
   wearing kit colours, not as the approved header. Every
   declaration below is copied from section 6 and section 23
   unchanged, apart from the one addition marked in place; only
   the selectors are new.

   Scope: every selector is under .mv-nav, which is on the header
   navigation widget and nowhere else, so nothing here can reach
   page content.

   Checked against the server side render of header template 191
   (.foreman/scratch/wp-build/render-header.html) rather than
   assumed: the menu container is a <nav>, the pointer effect is
   e--pointer-none so Elementor draws no :before or :after
   decoration that would need suppressing, and post-191.css
   carries no typography or spacing for this widget, so the panel
   is not competing with the rules below (conversion contract
   invariant 5). If anyone later sets nav typography, padding or
   spacing in the widget's Style panel, Elementor writes it at a
   higher specificity than this section and the panel will win.
   Keep those controls at their defaults.

   Part d1 of the source file, which zeroes Elementor's container
   padding on the chrome bars, is deliberately NOT merged here.
   It is not navigation, it reaches the footer as well as the
   header, those paddings are already set as panel values on
   templates 191 and 192, and one of its declarations (16px of
   block padding on .mv-header__inner) would change the header
   from what the panel renders today. Recorded as a concern for
   the lead instead.
   ============================================================ */

/* --- the list ----------------------------------------------- */
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 18px;
  margin: 0;
  padding: 0;
  list-style: none;
}
/* margin: 0 is the one addition to the source file. Elementor's
   horizontal layout writes its own spacing on the top level
   item, which would add to the 18px gap above. */
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li {
  position: relative;
  margin: 0;
}

/* top level and submenu links, from section 6's
   `.mv-nav a, .mv-dropdown__trigger` */
.mv-nav .elementor-nav-menu a.elementor-item,
.mv-nav .elementor-nav-menu a.elementor-sub-item {
  display: inline-block;
  padding: 6px 2px;
  background: transparent;
  border: 0;
  font-family: var(--mv-font);
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--mv-charcoal);
  text-decoration: none;
  fill: currentColor;
}
.mv-nav .elementor-nav-menu a.elementor-item:hover,
.mv-nav .elementor-nav-menu a.elementor-item:focus,
.mv-nav .elementor-nav-menu a.elementor-sub-item:hover,
.mv-nav .elementor-nav-menu a.elementor-sub-item:focus { color: var(--mv-red-deep); }

/* current page and current section, replacing
   `[aria-current="page"]` and `.mv-dropdown__trigger.is-current` */
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.current-menu-item > a.elementor-item,
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.current-menu-ancestor > a.elementor-item,
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.current-menu-parent > a.elementor-item {
  color: var(--mv-red-deep);
  border-bottom: 2px solid var(--mv-red-deep);
}
.mv-nav .elementor-nav-menu .sub-menu li.current-menu-item > a.elementor-sub-item {
  color: var(--mv-red-deep);
  font-weight: 700;
}

/* the caret. The static site set it in the trigger's own markup
   as a 9662 glyph; Elementor renders an inline svg in a
   span.sub-arrow, so it only needs sizing and a gap. */
.mv-nav .elementor-nav-menu .sub-arrow {
  display: inline-flex;
  align-items: center;
  margin-left: 6px;
}
.mv-nav .elementor-nav-menu .sub-arrow svg {
  width: 9px;
  height: 9px;
}

/* the dropdown panel, from `.mv-dropdown__menu` */
.mv-nav .elementor-nav-menu--main ul.sub-menu {
  position: absolute;
  top: calc(100% + 8px);
  left: -14px;
  z-index: 40;
  min-width: 220px;
  margin: 0;
  padding: 8px;
  list-style: none;
  background: var(--mv-cream);
  border: 1px solid var(--mv-line);
  border-radius: var(--mv-radius);
  box-shadow: 0 1px 2px rgba(42, 39, 36, .08), 0 14px 30px rgba(42, 39, 36, .12);
}
.mv-nav .elementor-nav-menu--main ul.sub-menu a.elementor-sub-item {
  display: block;
  padding: 9px 12px;
  border-radius: 6px;
}
.mv-nav .elementor-nav-menu--main ul.sub-menu a.elementor-sub-item:hover { background: var(--mv-sand); }

/* section 23's tightening, unchanged values */
@media (max-width: 1240px) {
  .mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu { gap: 4px 14px; }
  .mv-nav .elementor-nav-menu a.elementor-item { font-size: 14px; }
}
@media (max-width: 1040px) {
  .mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu { gap: 4px 11px; }
  .mv-nav .elementor-nav-menu a.elementor-item { font-size: 13.5px; }
}

/* the burger, from `.mv-navtoggle`. Elementor shows it at its
   own tablet breakpoint, 899px, where the static site used
   860px. Either accept the 39px difference or move the widget's
   Breakpoint control to Mobile and add a media query here. */
.mv-nav .elementor-menu-toggle {
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 14px;
  background: transparent;
  border: 1.5px solid var(--mv-charcoal);
  border-radius: 999px;
  color: var(--mv-charcoal);
  font-size: 15px;
  font-weight: 700;
}
.mv-nav .elementor-menu-toggle svg { width: 18px; height: 18px; fill: currentColor; }

/* the off-canvas list Elementor drops below the header, from
   section 23's 860px block */
.mv-nav nav.elementor-nav-menu--dropdown ul.elementor-nav-menu { padding: var(--mv-s3) 0 var(--mv-s1); }
.mv-nav nav.elementor-nav-menu--dropdown li + li { border-top: 1px solid var(--mv-line); }
.mv-nav nav.elementor-nav-menu--dropdown a.elementor-item,
.mv-nav nav.elementor-nav-menu--dropdown a.elementor-sub-item {
  display: block;
  width: 100%;
  padding: 12px 0;
  font-size: 16px;
  text-align: left;
}
.mv-nav nav.elementor-nav-menu--dropdown ul.sub-menu {
  position: static;
  min-width: 0;
  margin: 0 0 12px;
  padding: 4px 0 4px 14px;
  border: 0;
  border-left: 2px solid var(--mv-line);
  border-radius: 0;
  box-shadow: none;
  background: transparent;
}

/* ============================================================
   SECTION 40: proof-page glue fixes (FIX2)
   14 September 2026
   ------------------------------------------------------------
   Five corrections found on the first converted page, /stand/,
   and on the header and footer templates around it. None of
   them is a design change. Each one restores what the static
   stylesheet already produced, after the Elementor DOM moved an
   element out from under the selector that had been styling it,
   or after an Elementor rule outweighed it. Every value below is
   copied from the section named in the comment above it, byte
   for byte. Nothing here is new styling.

   Three of the five (40-c, 40-d, 40-e) are systemic: they were
   found on one page but they affect every page that uses the
   same class, so they are fixed for the whole site here rather
   than page by page.
   ============================================================ */

/* --- 40-a. The PDPA line inside the join card ----------------
   The static markup put the paragraph directly inside the card:

     div.mv-joincard > p.mv-pdpa

   so section 15's `.mv-joincard > p` (0,1,1) beat section 15's
   own `.mv-pdpa` (0,1,0) and the line set at 16px. In Elementor
   the paragraph is written by a text editor widget, so its real
   parent is that widget's div and the child combinator no
   longer matches. The line falls back to its own 13px, which is
   a visible shrink against the approved page.

   Below is section 15's `.mv-joincard > p` restated for the
   paragraphs a text editor widget puts inside the card. At
   (0,2,1) it clears `.mv-pdpa` (0,1,0). It sets those two
   declarations and no others, so `.mv-pdpa` keeps its own
   margin-top and line-height, exactly as in the static cascade.
   The colour is the same token either way, so the card reads
   correctly in a dark band as well: .mv-band--dark redefines
   --mv-soft rather than overriding this selector. */
.mv-joincard .elementor-widget-text-editor p {
  font-size: 16px;
  color: var(--mv-soft);
}

/* --- 40-b. Natural ratio photographs -------------------------
   Glue rule 38-b4, `.elementor-widget-image.mv-photo > img`
   (0,2,1), forces height 100% so a photograph fills the aspect
   ratio box its wrapper carries. Section 13's
   `.mv-photo--natural img` (0,1,1) is the switch that turns that
   off for images which must keep their own proportions, and it
   loses. The archived petition page on /stand/ is the first
   casualty; every other mv-photo--natural image on the site
   would distort the same way.

   Restating height auto one class heavier ties 38-b4 at (0,2,1)
   and wins on source order, this section being later in the
   file. Section 13's object-fit contain is not touched by 38-b4
   and still applies. Checked rather than assumed: the only three
   rules in this stylesheet that set a height on an img are the
   global `img { height: auto }` in section 3, section 13's
   `.mv-photo--natural img`, and 38-b4 itself, so nothing above
   (0,2,1) re-forces a height here. */
.elementor-widget-image.mv-photo--natural > img { height: auto; }

/* --- 40-c. The brand wordmark in the header and footer -------
   Section 30 sizes the client's wordmark artwork on the image
   itself:

     img.mv-brand__logo             display block, 20px, auto
     img.mv-brand__logo--footer     24px
     max-width 900px                18px

   In Elementor the class can only ride the image WIDGET, so
   mv-brand__logo lands on the wrapper div and the img inside it
   keeps its natural 613 by 164. The header and footer wordmarks
   render at roughly eight times their intended height.

   The rules below push section 30's declarations down onto the
   img. Specificity is (0,3,1), one class more than is needed to
   clear Elementor's own `.elementor-widget-image img` (0,1,1)
   from widget-image.min.css; the extra class buys a margin over
   a per-element width rule from the widget's Style panel, which
   Elementor would write at (0,3,1) into post-191.css or
   post-192.css. Neither of those files carries one today, and
   per conversion contract invariant 5 the panel controls stay at
   their defaults, but the wordmark is not the place to depend on
   that. The width and height attributes WordPress prints for the
   full size attachment are presentational hints and lose to any
   declaration here.

   Source order is section 30's, deliberately: the footer's 24px
   sits before the 900px query, and both selectors weigh the
   same, so below 900px the footer wordmark drops to 18px along
   with the header one. That is what the static site does. It is
   copied, not corrected.

   display block is restated because Elementor's widget CSS sets
   the img to inline-block, and the wrapper's margin is zeroed
   because the header wordmark is not the last widget in the
   brand link and would otherwise take Elementor's inter-widget
   margin, which the static markup never had. */
.elementor-widget.elementor-widget-image.mv-brand__logo,
.elementor-widget.elementor-widget-image.mv-brand__logo--footer {
  margin: 0;
}
.elementor-widget.elementor-widget-image.mv-brand__logo > img {
  display: block;
  height: 20px;
  width: auto;
}
.elementor-widget.elementor-widget-image.mv-brand__logo--footer > img { height: 24px; }
@media (max-width: 900px) {
  .elementor-widget.elementor-widget-image.mv-brand__logo > img { height: 18px; }
}

/* --- 40-d. Measures on widget wrappers and containers --------
   THE DEFEAT MECHANISM. Elementor's frontend.min.css carries

     .e-con.e-con > .e-con-inner > .elementor-widget,
     .elementor.elementor .e-con > .elementor-widget
       { max-width: 100% }

   Both branches weigh (0,4,0). Every measure in this stylesheet
   is written as a single class, (0,1,0), because in the static
   markup the class sat on the element itself. The moment a page
   worker puts that class on an Elementor WIDGET WRAPPER, which
   is where the contract says heading and image classes go, the
   Elementor rule outweighs it by three classes and the cap is
   simply gone. The petition frame on /stand/ carries
   mv-photo--small, which caps at 480px, and rendered at 1070px.
   Every prose measure on a heading widget goes the same way: a
   lede that should stop at 60ch runs the full 1092px band.

   Containers are hit less hard. A nested .e-con takes no
   max-width from Elementor at all, but a TOP LEVEL one takes
   `:is(.elementor-section-wrap,[data-elementor-id]) > .e-con
   { max-width: min(100%, var(--width)) }` at (0,2,0), which
   still beats a single class.

   THE FORM OF THE FIX. Each cap is restated once, unchanged,
   against the wrapper. The prefix `.elementor.elementor` is the
   same doubling trick Elementor uses in the rule above; with
   `.elementor-element.elementor-widget` after it the selector
   weighs (0,5,0) and wins outright, so nothing here depends on
   whether the child stylesheet happens to be printed after
   elementor frontend.min.css. Do not trim the prefix back: at
   (0,4,0) these rules tie and the outcome becomes an enqueue
   order accident.

   Contextual overrides are restated too, at the weight their own
   context gives them, or the hero displays would widen from 15ch
   and 17ch back to the base 20ch.

   The list is every max-width in this stylesheet that is
   attached to a class the contract puts on a widget wrapper or a
   container. Measures that live on markup INSIDE a text editor
   widget are not here and need nothing: a plain <p class="mv-src">
   is not a .elementor-widget and Elementor never touches it.
   Images inside these frames keep working through 38-b4 and
   40-b, which are untouched. */

/* 40-d.1 prose measures on a heading widget wrapper. Each value
   is the one the class's own rule above declares. */
.elementor.elementor .elementor-element.elementor-widget.mv-display { max-width: 20ch; }
.elementor.elementor .elementor-element.elementor-widget.mv-display--sm { max-width: 24ch; }
.elementor.elementor .elementor-element.elementor-widget.mv-lede { max-width: 60ch; }
.elementor.elementor .elementor-element.elementor-widget.mv-body { max-width: 52ch; }
.elementor.elementor .elementor-element.elementor-widget.mv-fineprint { max-width: 52ch; }
.elementor.elementor .elementor-element.elementor-widget.mv-source__title { max-width: 46ch; }
.elementor.elementor .elementor-element.elementor-widget.mv-pdpa { max-width: 46ch; }
.elementor.elementor .elementor-element.elementor-widget.mv-stat__label { max-width: 34ch; }
.elementor.elementor .elementor-element.elementor-widget.mv-stat__source { max-width: 42ch; }
.elementor.elementor .elementor-element.elementor-widget.mv-figblock__what { max-width: 30ch; }
.elementor.elementor .elementor-element.elementor-widget.mv-footer__line { max-width: 34ch; }
.elementor.elementor .elementor-element.elementor-widget.mv-footer__notice { max-width: 78ch; }
.elementor.elementor .elementor-element.elementor-widget.mv-announce__inner { max-width: var(--mv-maxw); }

/* 40-d.2 mv-measure, which the contract allows on a text editor
   widget wrapper as well as on a container, from section 11. */
.elementor.elementor .elementor-element.elementor-widget.mv-measure,
.elementor.elementor .e-con.mv-measure { max-width: 52ch; }

/* 40-d.3 frames and plates. mv-photo--small rides an image
   widget (section 13). mv-search is the container the search
   band's form becomes (section 16). mv-bottle__figure is a
   container and the cap is on the img inside it (section 27),
   where it was tying with Elementor's own `.elementor img
   { max-width: 100% }` at (0,1,1) and turning on print order. */
.elementor.elementor .elementor-element.elementor-widget.mv-photo--small { max-width: 480px; }
.elementor.elementor .e-con.mv-search { max-width: 720px; }
.elementor.elementor .mv-bottle__figure img { max-width: 519px; }

/* 40-d.4 the contextual measures that must stay narrower than
   the base ones above: the two illustrated heroes and the plain
   hero copy column. Without these the display would widen from
   15ch or 17ch to 40-d.1's 20ch. */
.elementor.elementor .mv-hero__copy .elementor-element.elementor-widget.mv-display { max-width: 17ch; }
.elementor.elementor .mv-hero--gi .elementor-element.elementor-widget.mv-display { max-width: 17ch; }
.elementor.elementor .mv-hero--gi .elementor-element.elementor-widget.mv-lede { max-width: 46ch; }
.elementor.elementor .mv-hero--sketch .mv-hero__copy .elementor-element.elementor-widget.mv-display { max-width: 15ch; }
.elementor.elementor .mv-hero--sketch .mv-hero__copy .elementor-element.elementor-widget.mv-lede { max-width: 46ch; }

/* --- 40-e. Completing the heading pass-down of 38-b2 ---------
   38-b2 hands a heading widget's own computed type down to the
   tag inside it with `font: inherit` and friends, at

     .elementor-widget-heading.mv-kicker > .elementor-heading-title

   which weighs (0,2,1). Directly above it, 38-b1 restates the
   default size for each tag at

     .elementor-element.elementor-widget-heading > p.elementor-heading-title

   which weighs (0,2,2), because of the element name. b1 is the
   heavier selector, so on every heading widget that carries a
   b2 class the four properties b1 declares win and the class's
   own type never reaches the tag: font-size, font-weight,
   line-height and letter-spacing. All 46 classes on the b2 list
   are affected, on every tag, since b1 has a rule for h1 to h6
   and one for p, span and div.

   It shows up worst on mv-kicker, which is built as a `p`
   (contract section 3, a kicker is a label, not a heading): the
   static 12.5px / 700 / 1.4 / 0.14em uppercase came out as
   17px / 400 / 1.6 / normal, keeping only its uppercase and its
   accent colour, because those two are the properties b1 does
   not set.

   The fix is specificity, not more declarations. The block below
   is 38-b2's selector list and its declarations, unchanged, with
   the two other classes the widget wrapper always carries,
   elementor-element and elementor-widget, added to each
   selector. That makes it (0,4,1), which clears b1's (0,2,2) on
   class count for every tag at once. 38-b2 itself is left in
   place: it is still correct, just outweighed, and this file is
   appended to rather than rewritten.

   If a class is ever added to the 38-b2 list, add it here too or
   it will be silently flattened to the tag default. */
.elementor-element.elementor-widget.elementor-widget-heading.mv-display > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-display--sm > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-h2 > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-kicker > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-lede > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-lede--sm > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-meta > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-body > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-fineprint > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-label > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-flag > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-tag > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-card__kicker > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-card__title > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-note__h > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-source__no > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-source__title > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-source__meta > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-timeline__when > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-toc__h > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-rail__h > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-argument__who > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-figblock__n > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-figblock__what > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-footer__h > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-pathway__title > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-pathway__desc > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-pathway__go > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-qcard__meta > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-stat__figure > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-stat__label > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-stat__source > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-doc__title > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-doc__meta > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-pullquote__text > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-pullquote__meta > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-sharebar__label > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-searchcount > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-search__hint > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-announce__inner > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-footer__line > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-footer__notice > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-footer__meta > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-wordmark > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-brand__sub > .elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-pdpa > .elementor-heading-title {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  word-spacing: inherit;
  text-transform: inherit;
  text-align: inherit;
  margin: 0;
}

/* --- 40-f. The five gaps 40-e cannot close on its own --------
   40-e hands the WHOLE font down with `font: inherit`, which is
   right for a class that declares all four of font-size,
   font-weight, line-height and letter-spacing, and that is 27 of
   the 46. For the other 19 it hands down the inherited body
   value for whatever the class does not declare.

   On a p, span, label or div that is harmless and in fact exact:
   38-b1 gives those tags 17px / 400 / 1.6 / normal, which is the
   body value, so inheriting it and being told it are the same
   thing. On an h1 to h6 they differ, and the static site gave
   the element the TAG default for anything its class left
   unset, because in the static markup the class and the tag were
   one element.

   Audited against the static tree, five classes ride a heading
   tag AND leave one of the four unset:

     mv-note__h    h2, h3   line-height
     mv-toc__h     h2       line-height
     mv-rail__h    h2       line-height
     mv-footer__h  h2       line-height
     mv-display--sm  h1, h2 font-weight, line-height, letter-spacing

   Everything else on the b2 list either declares all four or
   never rides a heading. The values below are 38-b1's own, per
   tag, copied verbatim: if 38-b1's tag defaults are ever
   retuned, retune these with them. Every tag is covered, not
   just the ones in use, so a worker who picks h4 instead of h3
   does not reopen this.

   mv-display--sm is used both alone (research.html h2) and
   paired with mv-display (every h1). Paired on an h1 the tag
   default and mv-display's own values are identical, so this
   rule is a no-op there. Paired on an h2 it would give 1.1 where
   mv-display asks 1.05; no such pairing exists in the static
   tree, and if one is ever built the pair needs its own rule.

   THE CLEANER REFACTOR, for whoever next rewrites section 38:
   put the tag defaults on the WRAPPER at zero specificity,
   `:where(.elementor-widget-heading:has(> h2.elementor-heading-title))
   { ... }`, so the wrapper behaves exactly like the static
   heading element and any mv- class at (0,1,0) layers over it.
   Then 40-e's `font: inherit` is exact for every class and this
   block and its audit list both disappear. It was not done here
   because it touches every heading widget on the site and this
   ticket's blast radius is five classes. */
.elementor-element.elementor-widget.elementor-widget-heading.mv-note__h > h1.elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-toc__h > h1.elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-rail__h > h1.elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-footer__h > h1.elementor-heading-title { line-height: 1.05; }
.elementor-element.elementor-widget.elementor-widget-heading.mv-note__h > h2.elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-toc__h > h2.elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-rail__h > h2.elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-footer__h > h2.elementor-heading-title { line-height: 1.1; }
.elementor-element.elementor-widget.elementor-widget-heading.mv-note__h > :is(h3, h4, h5, h6).elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-toc__h > :is(h3, h4, h5, h6).elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-rail__h > :is(h3, h4, h5, h6).elementor-heading-title,
.elementor-element.elementor-widget.elementor-widget-heading.mv-footer__h > :is(h3, h4, h5, h6).elementor-heading-title { line-height: 1.2; }
.elementor-element.elementor-widget.elementor-widget-heading.mv-display--sm > h1.elementor-heading-title {
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.03em;
}
.elementor-element.elementor-widget.elementor-widget-heading.mv-display--sm > h2.elementor-heading-title {
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.03em;
}
.elementor-element.elementor-widget.elementor-widget-heading.mv-display--sm > :is(h3, h4, h5, h6).elementor-heading-title {
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -0.02em;
}

/* ============================================================
   SECTION 41: chrome link colours the kit repaints (FIX3)
   14 September 2026
   ------------------------------------------------------------
   The top utility bar rendered its five social links and their
   icons in deep red on the deep red band, which is invisible.
   The same cause reaches the announcement bar link and the
   footer link lists, so all three are restored together here.

   Cause. Kit post 8 emits exactly two selectors that touch a
   link, and nothing anywhere in the kit touches a button:

     .elementor-kit-8 a        color: var(--e-global-color-primary)   (0,1,1)
     .elementor-kit-8 a:hover  color: var(--e-global-color-text)      (0,2,1)

   with --e-global-color-primary #B7302A, which is the top bar's
   own ground, and --e-global-color-text #2A2724.

   The static site never set a link colour on these three pieces
   of chrome. The bar set a colour on itself and the links
   INHERITED it, or a single class rule carried it. Inheritance
   does not happen once the kit paints the anchor directly, and
   a single class rule ties or loses:

     section 33  .mv-social__link   color var(--mv-white)   (0,1,0)  loses
     section 26  .mv-announce a     color var(--mv-white)   (0,1,1)  ties the
                 base rule, loses the hover rule
     section 7   .mv-footer__list a color var(--mv-cream)   (0,1,1)  same

   Fix. Each rule below is (0,3,1): three classes and one type.
   That clears BOTH kit rules on specificity alone, so none of
   this depends on which stylesheet is enqueued last, which is
   the part a tie leaves to chance. Because (0,3,1) also clears
   the kit's :hover rule at (0,2,1), no hover colour is restated
   below: the static hover rules for these links change
   text-decoration and opacity only and are left exactly as they
   are in sections 7, 26 and 33.

   Every value is the token the named static section uses, byte
   for byte. No new colour, no new token, no new behaviour.

   Checked and deliberately NOT given a rule:
   - the BM and EN controls are a button and a span, not
     anchors, and the kit has no button selector at all, so
     section 33's .mv-topbar .mv-lang__btn (0,2,0) is unopposed;
   - the social SVGs need no fill rule. Section 33's
     .mv-social__icon sets fill currentColor and the path
     carries fill="currentColor", so both follow the colour
     restored in 41-a, and the kit sets no fill anywhere;
   - the main menu is already safe: section 39's
     .mv-nav .elementor-nav-menu a.elementor-item is (0,3,1);
   - the header brand link does lose its .mv-brand color inherit
     (0,1,0) to the kit, but it wraps an image and a heading
     widget whose colour comes from the heading pass-down, so no
     text of its own takes the red. Left alone.

   Not fixed here, and raised with the lead instead, because it
   is site-wide body copy rather than chrome: section 3's bare
   `a` rule (0,0,1) loses to the kit base rule, so a link inside
   a dark band takes #B7302A rather than that band's re-pointed
   --mv-accent, and the kit hover rule at (0,2,1) turns most
   body links #2A2724 on hover.
   ============================================================ */

/* --- 41-a. The top utility bar -------------------------------
   From section 33, .mv-social__link. The five social links are
   the only anchors on this bar. */
.e-con.mv-topbar .mv-topbar__inner a { color: var(--mv-white); }

/* --- 41-b. The announcement bar ------------------------------
   From section 26, .mv-announce a. */
.e-con.mv-announce .mv-announce__inner a { color: var(--mv-white); }

/* --- 41-c. The footer link lists -----------------------------
   From section 7, .mv-footer__list a. All twenty five footer
   links sit inside a ul.mv-footer__list, so this reaches every
   one of them. */
.e-con.mv-footer .mv-footer__list a { color: var(--mv-cream); }

/* ============================================================
   SECTION 42: body copy link colours, the caption a text editor
   cannot class, and two questions answered (FIX4)
   14 September 2026
   ------------------------------------------------------------
   Section 41 fixed the three pieces of CHROME the kit repainted
   and handed the rest of the same cause to the lead:

     .elementor-kit-8 a        color var(--e-global-color-primary)  (0,1,1)
     .elementor-kit-8 a:hover  color var(--e-global-color-text)     (0,2,1)

   with primary #B7302A and text #2A2724, read out of
   uploads/elementor/css/post-8.css, not assumed.

   Two things go wrong in body copy.

   1. Section 3's bare `a { color: var(--mv-accent) }` is (0,0,1)
      and loses. On a light band that is invisible, because
      --mv-accent IS #B7302A there. Inside .mv-band--dark the
      band re-points --mv-accent to --mv-red-light #F2A79B, and
      the kit paints #B7302A on charcoal instead. Same for the
      MOVE on air panel, which re-points the same token.

   2. The static site has NO bare `a:hover` rule at all. A body
      link does not change colour when you point at it. The kit
      rule at (0,2,1) turns every link that has no heavier rule
      of its own #2A2724 on hover, which on a dark band is very
      close to the band itself.

   Fix. Every rule below is the static rule with `body` and the
   kit's own body class in front of it. That adds exactly one
   type and one class to each, so the ORDER BETWEEN the static
   rules is preserved (adding the same amount to both sides of a
   specificity comparison cannot change its result), while the
   whole group clears both kit rules on specificity alone rather
   than on enqueue order.

     base    body.elementor-kit-8 a          (0,1,2) > kit (0,1,1)
     hover   body.elementor-kit-8 a:hover    (0,2,2) > kit (0,2,1)

   Which components are restated: a component appears below ONLY
   where leaving it out would leave a computed colour different
   from the static site. So `.mv-link` at rest and `.mv-src a`
   are absent, because both resolve to var(--mv-accent) either
   way; `.mv-link:hover` is present, because it resolves to
   var(--mv-ink) and the base hover rule would otherwise take it.

   Checked and NOT given a rule, with the reason:
   - button widgets. `.elementor-widget-button.mv-btn > .elementor-button`
     and its two modifiers are (0,3,0) in glue 38-b5, and
     `.mv-form .e-form__buttons .elementor-button` is (0,3,0) in
     38-b6. All four clear the base hover at (0,2,2). No raw
     `a class="mv-btn"` exists in any Elementor document on this
     site (checked across every published page and template), so
     buttons are only ever widgets here;
   - the main menu. Section 39 is (0,3,1) at rest and (0,4,1) on
     hover, both above the rules below;
   - the top bar, the announcement bar and the footer lists.
     Section 41 is (0,3,1), above the base hover, so none of the
     three changes colour when pointed at;
   - `.mv-eventcard__cta` is a span inside the card anchor, not
     an anchor, so no `a` rule reaches it.

   Still open and NOT fixed here, raised for the lead: the same
   kit rule also sets font-family, font-size 16px, font-weight
   700 and line-height 1.2em on every anchor, from the Accent
   global typography. The static site sets no type on a bare `a`
   at all, so an inline link in body copy is currently bolder,
   smaller and tighter than the sentence around it. That is a
   second defect with the same cause and a wider blast radius
   than colour: neutralising it means restating the type of
   every anchor component as well, or clearing the kit's own
   Link controls so it emits no `a` rule. Colour only is fixed
   below, because that is what this ticket scoped.
   ============================================================ */

/* --- 42-a. Body copy links ----------------------------------- */

/* a1. The base. The hover value is the rest value on purpose:
   the static stylesheet has no `a:hover`, so a body link keeps
   its colour, and the only way to say that against a kit rule
   is to say it. */
body.elementor-kit-8 a { color: var(--mv-accent); }
body.elementor-kit-8 a:hover { color: var(--mv-accent); }

/* a2. Components. Values are the tokens the named static
   section already uses, byte for byte. Where the static has no
   hover rule, the hover line repeats the rest value, which is
   what the static cascade computes. */

/* section 8, .mv-link:hover */
body.elementor-kit-8 .mv-link:hover { color: var(--mv-ink); }

/* section 16, .mv-chip and .mv-chip:hover */
body.elementor-kit-8 .mv-chip { color: var(--mv-ink); }
body.elementor-kit-8 .mv-chip:hover { color: var(--mv-red-deep); }

/* section 17, .mv-pathway */
body.elementor-kit-8 .mv-pathway,
body.elementor-kit-8 .mv-pathway:hover { color: var(--mv-ink); }

/* section 22a, .mv-card--link. Covers the event cards too: they
   are a.mv-card.mv-card--link.mv-eventcard */
body.elementor-kit-8 .mv-card--link,
body.elementor-kit-8 .mv-card--link:hover { color: inherit; }

/* section 34, .mv-share__btn. Three of the four are anchors, the
   native share control is a button and the kit never touched
   it; both are restated so the row cannot split in two. */
body.elementor-kit-8 .mv-share__btn { color: var(--mv-charcoal); }
body.elementor-kit-8 .mv-share__btn:hover { color: var(--mv-red-deep); }

/* section 6, .mv-skip. Cream on the charcoal chip. This one is
   a live defect, not a guard: the kit is painting the focused
   skip link #B7302A on #2A2724 today. */
body.elementor-kit-8 .mv-skip,
body.elementor-kit-8 .mv-skip:focus,
body.elementor-kit-8 .mv-skip:hover { color: var(--mv-cream); }

/* section 6, .mv-brand. Section 41 left this alone because
   nothing inside the brand link renders the anchor's own
   colour, which is still true. It is restated only so the
   anchor's computed colour matches the static page. */
body.elementor-kit-8 .mv-brand,
body.elementor-kit-8 .mv-brand:hover { color: inherit; }

/* section 9, .mv-card__title a */
body.elementor-kit-8 .mv-card__title a { color: inherit; }
body.elementor-kit-8 .mv-card__title a:hover { color: var(--mv-accent); }

/* section 18, .mv-qcard h3 a */
body.elementor-kit-8 .mv-qcard h3 a { color: inherit; }
body.elementor-kit-8 .mv-qcard h3 a:hover { color: var(--mv-accent); }

/* section 19, .mv-toc__list a. The hover rule there also sets
   border-bottom-color, which no kit rule touches, so only the
   colour is restated. */
body.elementor-kit-8 .mv-toc__list a { color: var(--mv-ink); }
body.elementor-kit-8 .mv-toc__list a:hover { color: var(--mv-accent); }

/* section 19, .mv-source__title a */
body.elementor-kit-8 .mv-source__title a { color: inherit; }
body.elementor-kit-8 .mv-source__title a:hover { color: var(--mv-accent); }

/* --- 42-b. Kit container padding: NOT a rule ------------------
   Recorded here because the change belongs to this section's
   work and leaves no trace in this file.

   Kit post 8 had container_padding empty. Elementor's own
   frontend.css then falls back to ten pixels:

     .e-con { --padding-top: var(--container-default-padding-top, 10px);
              ... same for right, bottom and left }
     .e-con { padding-inline-start: var(--padding-inline-start);
              padding-inline-end:   var(--padding-inline-end); }
     .e-con-full, .e-con > .e-con-inner {
              padding-block-start: var(--padding-block-start);
              padding-block-end:   var(--padding-block-end); }

   so every container carried 10px on all four sides unless
   something overrode it. The kit setting is now an explicit 0
   on all four sides, and post-8.css emits

     .e-con{--container-default-padding-top:0px; ...}

   What that fixes. The contract builds the bare grouping divs
   of the static markup as unclassed containers, and no rule in
   this stylesheet gives them padding, so each one was inset by
   10px the static div never had. The same applies to every grid
   container (.mv-cols-2/3/4, .mv-split, .mv-stats, .mv-pathways,
   .mv-figures, .mv-withrail) and to .mv-figure, none of which
   are given padding in glue 38-a3. It also reached the band:
   .mv-bandinner is the one boxed container on a page, so it took
   10px inline on the outer element on top of the 24px gutter
   that .mv-bandinner > .e-con-inner draws, and 10px block on the
   inner. Every band was 20px taller than the static page and,
   below about 1160px, 20px narrower in the measure.

   What else consumed the default, and why none of it moves:
   - bands, cards and every other box: glue 38-a1 and 38-a4
     restate padding at .e-con.<class>, which is (0,2,0) against
     Elementor's (0,1,0), so the value never came from the
     default;
   - the header and footer templates: every container in 191 and
     192 carries an explicit 0 in the panel, except .mv-footer,
     whose section 7 padding shorthand at (0,1,0) beats the
     longhand from the default on order (the child sheet is
     enqueued last) and is unchanged either way;
   - the 404 template 193: its band is .e-con.mv-band, covered,
     and its .mv-bandinner gains the same correction as every
     other page;
   - widgets: the default is a container variable and never
     reached them.

   Risk accepted: any container that WANTED the 10px is now flat.
   None was found. Everything above was read from the stored
   documents, not assumed. Reversing it means putting the four
   kit padding fields back to empty and regenerating the CSS. */

/* --- 42-c. A figure caption a text editor cannot class --------
   Contract 7.1 step 4 transplants compliance.html's bare
   <figcaption> as a bare <p> in a text editor widget, because a
   heading widget would be wrong and Elementor's own caption
   control is only allowed on an unframed image. A bare <p> in a
   text editor renders at body size: 17px charcoal instead of
   13.5px in --mv-soft.

   Section 13 styles the two caption shapes in ONE block:

     .mv-figure figcaption,
     .mv-photo__caption { margin-top: 10px; font-size: 13.5px;
                          line-height: 1.5; color: var(--mv-soft);
                          max-width: 60ch; }

   so there is nothing to reconcile between them; the five
   declarations below are that block, unchanged.

   Scope. Only an UNCLASSED paragraph that is a direct child of a
   text editor widget that is a direct child of a .mv-figure
   container. p:not([class]) leaves p.mv-photo__caption,
   p.mv-src and p.mv-fineprint to their own rules, and the child
   combinator keeps the rule out of any transplanted block whose
   root is something else: the six-things hidden list on
   consumer-guide is a <div class="mv-vh"> and its paragraphs are
   inside that div, not children of the widget. Checked against
   the two .mv-figure containers built so far, on compliance: the
   guide plate figure, whose caption this is, and the MOH
   infographic figure, which uses Elementor's own caption and so
   is already reached by section 13's own figcaption selector.

   Bottom margin is not restated: the caption is the only child
   of its widget, and glue 38-b3's
   `.elementor-widget-text-editor > :last-child` already zeroes
   it. If a caption ever stops being the last child of its own
   widget, that is the line to revisit. */
.mv-figure > .elementor-widget-text-editor > p:not([class]) {
  margin-top: 10px;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--mv-soft);
  max-width: 60ch;
}

/* --- 42-d. The 860px nav question, answered -------------------
   Question: section 23 sets .mv-nav { display: none } below
   861px, written for the static hand built <nav class="mv-nav">,
   yet the Elementor burger was measured working at 375px. Which
   is true?

   Both. In the build, mv-nav is a CSS class on the nav menu
   WIDGET div (element a6994ed of template 191, settings
   dropdown: tablet, toggle: burger), and Elementor Pro's
   widget-nav-menu.min.css carries

     .elementor-widget-nav-menu .elementor-widget-container,
     .elementor-widget-nav-menu:not(:has(.elementor-widget-container)):not([class*=elementor-hidden-])
       { display: flex; flex-direction: column }

   The second selector is (0,3,0) and matches this widget, since
   this Elementor version prints no .elementor-widget-container.
   Section 23's .mv-nav is (0,1,0), so its display: none never
   applies. Everything else in that 860px block selects static
   markup that no longer exists (.mv-navtoggle, .mv-nav__list,
   .mv-dropdown__menu), so it is inert as well.

   What each width therefore shows, from the widget classes and
   the plugin's own media queries:

     375px      horizontal list hidden by Elementor's
                @media (max-width:1024px)
                .elementor-nav-menu--dropdown-tablet
                .elementor-nav-menu--main { display: none };
                burger shown. WORKS.
     800px      the same. WORKS.
     861-899px  the same. WORKS. There is nothing special about
                861: the static site's breakpoint plays no part.
     900-1024px the same. WORKS.
     1025px+    @media (min-width:1025px) hides the burger and
                the dropdown; the horizontal list shows. WORKS.

   So no width range leaves the header without a menu control,
   and no rule is needed for that. Do not re-litigate it.

   Two things that ARE worth knowing, neither of them a break:

   1. The switch point moved. The static site went to the burger
      at 860px; the build goes at 1024px, so between 861 and
      1024 the built header shows a burger where the approved
      design shows the full menu. Section 39's comment calls
      this a 39px difference at 899px; that is wrong, the
      plugin's tablet breakpoint here is 1024/1025 and the gap
      is 164px. Closing it means setting the widget's Breakpoint
      control to Mobile and adding a 861px query, which is a
      design decision, not a fix.

   2. The one rule below. What keeps the menu alive today is a
      third party selector that happens to outrank ours, and it
      is written with :has(). In a browser without :has()
      support the whole selector is invalid, Elementor's rule
      disappears, section 23 wins and the header loses its menu
      entirely below 861px. This restates the outcome at (0,2,0),
      which beats section 23's (0,1,0) and agrees with
      Elementor's (0,3,0), so the header no longer depends on
      that. Delete it if the lead would rather keep section 42
      to what was strictly asked for; it changes nothing in a
      browser that supports :has(). */
@media (max-width: 860px) {
  .elementor-widget-nav-menu.mv-nav { display: flex; }
}

/* ============================================================
   SECTION 43: the work page timeline, rebuilt as a real list
   (FIX5, 14 September 2026)
   ------------------------------------------------------------
   work.html line 121 builds its 16 timeline entries as an
   ordered list:

     <ol class="mv-mt4">
       <li><article class="mv-card mv-card--line" id="..."> ...

   Section 3 above sets `ul, ol { margin: 0 0 var(--mv-s3);
   padding-left: 20px; }` and nothing in this file resets the
   list style on that ol, so the approved static page shows the
   browser default decimal markers, 1 through 16, and exposes
   list semantics to a screen reader. The first build flattened
   the list to plain containers and lost both.

   The lead's ruling of 14 September 2026: the entries carry
   native image widgets, so the list cannot be transplanted into
   one text editor widget without taking those images out of
   Elementor's hands and breaking editor rule 9.1. Keep the
   widgets and rebuild the list around them instead. The wrapper
   container carries role="list" and the class mv-worklist, each
   of the 16 entry containers carries role="listitem", and the
   marker that a div does not draw is drawn here by a counter.
   Text only lists stay transplanted markup; this pattern is for
   a list whose items are cards containing images.

   Four notes for whoever changes this next.

   1. The bottom margin is written as margin-bottom, NOT as the
      static shorthand `margin: 0 0 var(--mv-s3)`. The wrapper
      also carries mv-mt4, which is one class; a two class
      shorthand here would win and silently zero the 32px of
      space above the list.
   2. The padding is written in full because Elementor writes
      padding longhands on every .e-con, so the 10px default has
      to be cleared on all four sides. The static ol has
      padding-left 20px and nothing else.
   3. top: 21px is measured, not guessed. A browser puts an
      outside marker on the baseline of the list item's first
      line box, which here is the card kicker, 26px of card
      padding down. Measured in Chrome against the static page
      at 1280px and at 375px: 21px at both, because neither the
      card's padding-top nor the kicker's 20px line box changes
      with width, and the built kicker keeps that same 20px line
      box (glue 38-b1 gives p.elementor-heading-title
      line-height 1.6 and b2 does not override it).
      `right: calc(100% + 1px)` walks the marker back over the
      card's own 1px mv-card--line border, because an absolutely
      positioned box is placed against its ancestor's PADDING
      box, so the marker lands exactly where the static one
      lands. The trailing space inside the content string is the
      gap a default decimal marker has, and white-space: pre is
      what keeps it.
   4. The marker is a ::before rather than a real ::marker, so
      unlike the static page a screen reader may read it in
      addition to the list position it already announces. That
      is the accepted cost of keeping the images as widgets. The
      CSS alternate text syntax (`content: counter(mvwork) ". "
      / ""`) would silence it, and is deliberately NOT used: a
      browser that does not parse it drops the whole declaration
      and the numbers disappear.

   Nothing else in this stylesheet styles these markers: there is
   no ::marker rule anywhere in the file, and no list-style
   declaration reaches this ol.
   ============================================================ */
.e-con.mv-worklist {
  margin-bottom: var(--mv-s3);
  padding: 0 0 0 20px;
  counter-reset: mvwork;
}
.e-con.mv-worklist > .e-con {
  counter-increment: mvwork;
}
.e-con.mv-worklist > .e-con::before {
  content: counter(mvwork) ". ";
  position: absolute;
  top: 21px;
  right: calc(100% + 1px);
  white-space: pre;
  font-family: var(--mv-font);
  font-size: 17px;
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: normal;
  color: var(--mv-charcoal);
  pointer-events: none;
}

/* ------------------------------------------------------------
   SECTION 43-a: the timeline's entry spacing
   (FIX6, 15 September 2026)
   ------------------------------------------------------------
   The rebuilt list was spacing its entries 44px apart where the
   approved static page spaces them 24px. Nothing is wrong with
   the markup. Two spacings were stacking.

   work.html gives entries 2 to 16 their space with one class on
   the list item, <li class="mv-mt3">, which section 3 above
   resolves to margin-top: var(--mv-s4), 24px. The first entry
   carries no class and so has no space above it. The build keeps
   that arrangement exactly: mv-mt3 sits on each entry container
   bar the first, and .mv-card itself declares no margin at all,
   so 24px is the whole of the static spacing.

   Elementor then adds its own on top. The wrapper is a flex
   container, and elementor/assets/css/frontend.min.css sets

     .elementor-element:where(.e-con-full,.elementor-widget)
       { gap: var(--row-gap) var(--column-gap) }

   while .e-con declares --row-gap: var(--widgets-spacing-row,
   20px). A flex gap does not collapse with a margin the way two
   block margins do, so every entry sat 20 + 24 = 44px below the
   one above it. The first entry measured correctly throughout,
   which is the tell: a gap has no effect before the first item.

   Zero the ROW gap on this one container and the spacing is the
   cards' own margin again, which is the spacing the client
   approved. The COLUMN gap is deliberately left alone: the
   entries are a single column, so it has nothing to do here, and
   removing it would be a change with no reason behind it.

   SPECIFICITY, since this rule has to win without !important.
   .e-con.mv-worklist is two classes, 0-2-0. The declaration it
   has to beat is Elementor's .elementor-element inside a
   :where(), which is 0-1-0, because :where() contributes
   nothing. 0-2-0 wins outright, so the result does not depend on
   which stylesheet the browser happens to load last, and it
   survives Elementor updating its own file. The shorthand
   versus longhand question (their gap against this row-gap)
   never arises either: that only decides ties, and this is not a
   tie. Nothing in this file or in the kit sets a gap on this
   container at higher specificity; a per-element gap would be
   0-3-0 and would win, which is one more reason contract
   invariant 5 keeps page workers out of the style controls.

   The other available route, redefining --row-gap: 0px on the
   wrapper, was NOT taken. Custom properties inherit, and
   .elementor-widget sits in the same :where() list, so a widget
   placed as a direct child of this container would silently lose
   its own internal row gap too. row-gap on the container reaches
   this container's own children and nothing else.
   ------------------------------------------------------------ */
.e-con.mv-worklist {
  row-gap: 0;
}

/* ------------------------------------------------------------
   SECTION 44: the articles pagination
   (FIX7, 15 September 2026)
   ------------------------------------------------------------
   The articles listing is a Loop Grid with pagination_type
   "numbers" and page_reload. Elementor Pro renders that footer,
   in elementor-pro/modules/posts/skins/skin-base.php, as

     <nav class="elementor-pagination" aria-label="Pagination">
       <span aria-current="page" class="page-numbers current">
         <span class="elementor-screen-only">Page</span>1</span>
       <a class="page-numbers" href="...">
         <span class="elementor-screen-only">Page</span>2</a>
       <span class="page-numbers dots">&hellip;</span>
     </nav>

   so there are exactly three things to style: the nav, a link,
   and the current page. Left alone the numbers arrive in the
   browser's own link blue at the theme's default size, which is
   the one place on this site where a control would not look
   like the site.

   Scope. The rule is written as .mv-band .elementor-pagination
   rather than against the archive document id (.elementor-353),
   because the document id changes if the template is ever
   rebuilt, while every piece of ported page content on this site
   sits inside a band. It is deliberately NOT scoped to the whole
   page: the header, the top bar, the announcement bar, the
   footer and the Elementor editor chrome all sit outside
   .mv-band and none of them is touched. As at this build the
   listing is the only Loop Grid on the site, so the rule matches
   one element in one place.

   Spacing is set as PADDING on each number rather than as a
   margin. Elementor writes its own margin on
   .page-numbers:not(:first-child) into the page's generated
   stylesheet at a specificity of four classes, which this file
   cannot beat without !important. Padding adds to that margin
   instead of arguing with it, and it has the better side effect
   of giving each number a touch target taller than the digit.

   Colour. Links take var(--mv-accent), which resolves to
   --mv-red-deep on the cream and sand bands and to the light red
   on a dark band, so the pagination follows a band the way every
   other link on the site does. The current page is charcoal and
   carries no underline, which is what distinguishes it: it is
   the one number that is not a link, and it should not look like
   one. Nothing here draws a box, a border or a shadow.

   Type is var(--mv-font) at the body size, so the numbers read
   as the site's own text. No transition is declared, so there is
   nothing for section 24's reduced-motion block to have to cover
   and nothing above this point in the file needs editing.
   ------------------------------------------------------------ */
.mv-band .elementor-pagination {
  margin-top: var(--mv-s6);
  font-family: var(--mv-font);
  font-size: 17px;
  line-height: 1.6;
}
.mv-band .elementor-pagination .page-numbers {
  display: inline-block;
  padding: 6px 10px;
  font-weight: 700;
  color: var(--mv-accent);
  text-decoration: underline;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 4px;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
.mv-band .elementor-pagination a.page-numbers:hover {
  color: var(--mv-ink);
}
.mv-band .elementor-pagination .page-numbers.current {
  color: var(--mv-ink);
  text-decoration: none;
}
.mv-band .elementor-pagination .page-numbers.dots {
  color: var(--mv-soft);
  font-weight: 400;
  text-decoration: none;
}
.mv-band .elementor-pagination .page-numbers:focus-visible {
  outline: 2px solid var(--mv-focus);
  outline-offset: 3px;
}

/* ------------------------------------------------------------
   SECTION 45: the native search form and the search results
   template (ticket E2, 15 September 2026)
   ------------------------------------------------------------
   Three small jobs, all of them consequences of moving search
   from the static site's client side script to WordPress's own
   search. Nothing above this point in the file is edited.

   --- 45-a. The search input -------------------------------

   The search band's form is transplanted markup, so the field
   is a raw <input class="mv-input" type="search">. That is the
   FIRST raw input in this build: every other field on the site
   is an Elementor Pro form field, which Elementor paints
   through its own .elementor-field rules at a specificity this
   file never has to argue with, so nothing has run into the
   theme's reset before now.

   hello-elementor/assets/css/reset.css, enqueued as the handle
   "hello-elementor" and live on this install, carries

     input[type=date], ... input[type=search], ... select,
     textarea { border: 1px solid #666; border-radius: 3px;
                padding: .5rem 1rem; transition: all .3s;
                width: 100% }

   That selector is (0,1,1). Section 15's .mv-input is (0,1,0).
   Specificity decides before stylesheet order does, so the
   reset wins on border, border radius, padding and transition,
   and the field arrives with a grey 3px cornered box instead of
   the sand bordered 8px one the approved design has. Width is
   100% in both, so that one is a tie in fact if not in form.

   .mv-search .mv-input is (0,2,0) and beats (0,1,1) outright,
   which is the same one class heavier discipline the rest of
   this file uses, so the outcome does not depend on which
   stylesheet the browser loads last. Only the four properties
   the reset actually takes are restated here; everything else
   about the field is still section 15's and is edited there.

   The submit button needs no rule. The reset's button block
   matches ours through [type=submit], which is also (0,1,0), so
   .mv-btn and .mv-btn--primary tie with it and win on order:
   the child stylesheet is enqueued after the reset. Verified
   property by property against the reset before this section
   was written.
   ------------------------------------------------------------ */
.mv-search .mv-input {
  padding: 12px 14px;
  border: 1px solid var(--mv-line-sand);
  border-radius: 8px;
  transition: border-color 150ms ease;
}

/* ------------------------------------------------------------
   --- 45-b. The results list ---------------------------------

   The results are an Archive Posts widget on the classic skin,
   one column, no thumbnail, no meta, no read more link. That
   skin prints its own markup, which no panel control can class:

     <article class="elementor-post elementor-grid-item">
       <div class="elementor-post__text">
         <h2 class="elementor-post__title"><a>...</a></h2>
         <div class="elementor-post__excerpt"><p>...</p></div>

   So the mapping has to happen here. These rules restate
   section 10's .mv-card, .mv-card__title and .mv-card__body on
   the widget's own class names, with no new values invented:
   every number below is copied from those three rules, so a
   result reads as the same card the rest of the site uses and
   there is one place to change a card, not two.

   Scope and weight. The selectors are written
   .mv-searchresults .mv-searchlist X, three classes, because
   the title is a bare h2 and .elementor-kit-8 h2 (0,1,1) paints
   a bare h2 at display size, 40px, through the kit's generated
   stylesheet. Two classes would already be enough; three keeps
   the rules inside the one band they belong to, so a future
   Archive Posts widget somewhere else on the site is not
   silently restyled by this section.

   The row spacing between results is Elementor's own grid gap,
   35px, which is close enough to the card spacing elsewhere on
   the site that overriding it would be a change with no reason
   behind it.

   Pagination needs no rule: section 44 already styles
   .mv-band .elementor-pagination, and this template's results
   band is a .mv-band.
   ------------------------------------------------------------ */
.mv-searchresults .mv-searchlist .elementor-post {
  background: var(--mv-card);
  border-radius: var(--mv-radius);
  padding: 26px 26px 24px;
}
.mv-searchresults .mv-searchlist .elementor-post__title {
  font-size: 23px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 0 0 10px;
}
.mv-searchresults .mv-searchlist .elementor-post__title a {
  color: inherit;
  text-decoration: none;
}
.mv-searchresults .mv-searchlist .elementor-post__title a:hover {
  color: var(--mv-accent);
}
.mv-searchresults .mv-searchlist .elementor-post__excerpt {
  font-size: 16px;
  line-height: 1.6;
  color: var(--mv-soft);
}
.mv-searchresults .mv-searchlist .elementor-post__excerpt p:last-child {
  margin-bottom: 0;
}

/* ------------------------------------------------------------
   --- 45-c. The empty state ----------------------------------

   The Archive Posts widget has a Nothing Found Message field,
   and Elementor Pro puts it through esc_html before printing
   it, in modules/theme-builder/skins/posts-archive-skin-base.php.
   The only way to turn that off is a PHP filter, and this build
   adds no PHP, so a message carrying a link to Learn cannot be
   typed into that field: the anchor would arrive on screen as
   its own source.

   So the field is left EMPTY on purpose. Elementor still prints

     <div class="elementor-posts-nothing-found"></div>

   whenever the query found nothing, empty or not, and the real
   line is an ordinary text editor widget sitting beside the
   list, carrying .mv-noresults on the WIDGET (not on the
   paragraph, so the whole widget goes and the band's flex gap
   goes with it). It is revealed by the presence of that div.

   Two things worth knowing.

   1. Leaving the field empty is also what keeps this build
      ASCII. Elementor's own default for it is "It seems we
      can't find what you're looking for." with a curly
      apostrophe in it, twice.

   2. The line is hidden by default and revealed by :has(),
      rather than shown by default and hidden by :not(:has()).
      In a browser without :has() support the first way shows
      nothing on an empty search; the second way would print
      "Nothing matched" above ten results. The first failure is
      the smaller one. :has() is already a dependency of this
      file, see section 42-d.

   Weight. The hide is (0,2,0). The reveal is (0,3,0), because
   :has() contributes the specificity of its argument, so it
   wins without needing to be written any heavier.
   ------------------------------------------------------------ */
.mv-searchresults .mv-noresults {
  display: none;
}
.mv-searchresults:has(.elementor-posts-nothing-found) .mv-noresults {
  display: block;
}

/* ------------------------------------------------------------
   --- 45-d. Putting section 24 back on top of 45-a ------------

   Section 24's reduced motion block lists .mv-input at (0,1,0)
   and switches its transition off. 45-a above had to restate
   that transition at (0,2,0) to get out from under the theme
   reset, and a heavier rule outside a media query still beats a
   lighter rule inside one, so 45-a would have quietly handed
   the field its transition back to a reader who has asked the
   operating system for less motion. This restates the switch
   off at the same weight as the rule that caused the problem.

   Section 24 itself is NOT edited: it is above this point in
   the file, it is correct for every other control it lists, and
   this section owns the problem it created.
   ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  .mv-search .mv-input { transition: none; }
}

/* ------------------------------------------------------------
   SECTION 46: the two illustrated heroes, copy back on top of
   the wash (client, 15 September 2026)
   ------------------------------------------------------------
   The client sent screenshots of the home hero and the Get
   involved hero with their headings washed out to nothing. The
   cause is a stacking accident from the conversion, not a
   change of design.

   In the static build the decoration layers and the copy were
   siblings inside the hero section, and the copy carried a
   z-index of its own:

     .mv-hero--sketch > .mv-container { position: relative;
                                        z-index: 2; }
     .mv-hero__sketch { position: absolute; z-index: 0; }
     .mv-hero__veil   { position: absolute; z-index: 1; }
     .mv-hero__fade   { position: absolute; z-index: 1; }

   That is static site.css section 31. Section 35 builds the Get
   involved hero the same way: .mv-hero__drawing at 0,
   .mv-hero__wash at 1, and .mv-hero--gi > .mv-container at 2.

   Three layers, three z-index values, and the copy deliberately
   above all of them at 2. The wash is an opaque cream gradient
   where it starts, so whatever it paints over disappears.

   Here the layers arrived as an HTML widget (.mv-herolayers)
   and the copy became an Elementor boxed container
   (.mv-bandinner). The layers kept their z-index values. The
   copy did not: Elementor gives the container position relative
   and leaves z-index at auto. A positioned element with z-index
   auto paints in tree order alongside the z-index 0 group,
   which still puts it above the drawing, but it paints BELOW
   anything with a positive z-index. So the veil and the wash,
   at z-index 1, painted over the heading, the lede and the
   buttons.

   The fix is the static rule, restated for the container class
   the conversion produced. Nothing about the layers changes and
   the gradients still render exactly as designed, behind the
   copy instead of over it.
   ------------------------------------------------------------ */
.mv-hero--sketch > .mv-bandinner,
.mv-hero--gi > .mv-bandinner {
  position: relative;
  z-index: 2;
}

/* The HTML widget carrying the layers has to stay unpositioned.
   It is a zero height div, so the layers inside it are
   positioned against the hero section itself, which is what
   gives them the section's full box. If the widget were ever
   given a position they would collapse into its zero height
   box, and a z-index on it would trap them in a stacking
   context of their own underneath the copy. Both are stated
   here so that a later rule has to argue with this section
   rather than break the heroes quietly. */
.mv-hero--sketch > .mv-herolayers,
.mv-hero--gi > .mv-herolayers {
  position: static;
  z-index: auto;
}

/* ============================================================
   SECTION 47: Get involved as a call to action
   15 September 2026 (client request, Michael, wave G)
   ------------------------------------------------------------
   A client change, and a deliberate divergence from the static
   build, which has no pill in its navigation. Two parts were
   asked for. "Articles" moves to second last so "Get involved"
   ends the menu, which is done in the WordPress menu itself
   (Primary, term 3: menu_order 24 on item 160 and 25 on item
   159, nothing in CSS). "Get involved" is then dressed as a
   call to action in the style of the home hero button.

   The class mv-nav-cta is on menu item 159 only, set in that
   item's CSS Classes field, so every selector below is locked
   to one item. Elementor prints the class on the li in BOTH
   navigations the widget renders, the desktop one and the
   burger dropdown, which is why both are styled here.

   THE VALUES are the hero button's own, read off
   .elementor-widget-button.mv-btn--primary > .elementor-button
   in section 38: fill var(--mv-red), white text, 999px radius,
   1.5px transparent border, weight 700, the two layer shadow,
   the 150ms transition, hover to var(--mv-red-deep) with a 1px
   lift, and the active nudge. The ticket calls the fill "deep
   red"; in this stylesheet the hero fill is var(--mv-red) and
   var(--mv-red-deep) is its hover, so the pair is mirrored as
   built rather than shifted a step darker at rest.

   THREE metrics are not copied, and the list gap is retuned.
   All four numbers were measured in the browser rather than
   chosen, because the header had no room to give.

   1. min-height 48px becomes 33px, and 32px below 1041px.
      The header row is 69.3px at 1280 and it is set by the
      brand block, 37.3px inside 16px of block padding on
      .mv-header__inner, while the menu sits at 30.9px. Anything
      that takes the menu past 37.3px takes the header with it.
      Measured: a 33px pill leaves the row at 69.3px and a 34px
      pill moves it to 70px, so 33px is the ceiling. At 1040px
      and below the brand drops to 18px and the MENU sets the
      header instead, at 64.3px, and there the ceiling is 32px.
      A 48px pill would have made the header about 80px.

   2. padding 0 26px becomes 0 15px, and 0 11px below 1241px.
   3. font-size 16px is not set at all, so the pill keeps the
      14.5px the menu already uses (14px and 13.5px in the two
      tightening steps below).
   4. the top level column gap steps down with them: 18px
      becomes 14px above 1240, 14px becomes 10px from 1240 to
      1041, and 11px becomes 8px at 1040 and below. The row gap
      of 4px is untouched.

   Why the gap had to move. The menu is flex-wrap: wrap, and
   before this change it already ran to 789.1px of the 802.4px
   the nav box gets at 1280: 13.3px of slack. Between 1041 and
   1100 there was 1.6px, and below 1061 the stock menu ALREADY
   WRAPS to two rows on its own (see the note at the foot of
   this section). A pill costs about 30px however it is drawn,
   so it could not be paid for out of that. Taking four pixels
   off each of the seven gaps returns 28px, which pays for it
   almost exactly, and 14px is not a new value in this design:
   it is what section 39 already uses below 1240px, applied
   40px earlier.

   Measured after the change, slack in the menu row, stock
   value first:

     1680  13.3 -> 10.5    1240  55.8 -> 63.8
     1280  13.3 -> 10.5    1100   1.6 ->  8.8
     1241  13.3 -> 10.5    1040 143.4 -> 144.4
                            900  11.7 ->  11.9

   and the header row is 69.3px at every width from 1101 up and
   64.3px from 1040 down, both unchanged from the stock build.

   PRE-EXISTING DEFECT, found here and NOT introduced by this
   section: between about 1041px and 1100px the brand block is
   still at its full width while the menu has not yet reached
   its 1040px tightening step, and the menu wraps to two rows,
   taking the header to about 100px. At 1060px the stock build
   is 38.4px short of the width it needs. This section improves
   that number by about 7px but cannot close it. Raised for the
   lead rather than papered over, because the fix is a decision
   about the header (an earlier burger breakpoint, or the brand
   strapline hiding sooner), not about this pill.

   If the brand block is ever made taller, or the menu gains or
   loses an item, every number above has to be measured again.
   ============================================================ */

/* --- 47-a. The list gap, retuned to make room ---------------- */

/* Scoped to its own window so section 39's two steps still
   own theirs. Same selector and specificity as section 39's
   (0,3,1), later in the file, so each of these wins inside its
   own query only. */
@media (min-width: 1241px) {
  .mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu { gap: 4px 14px; }
}
@media (max-width: 1240px) {
  .mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu { gap: 4px 10px; }
}
@media (max-width: 1040px) {
  .mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu { gap: 4px 8px; }
}

/* --- 47-b. The pill in the desktop menu ---------------------- */

/* (0,5,3), the same weight as section 39's link rule and after
   it in the file, so it wins on order. */
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-cta > a.elementor-item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 33px;
  margin-left: 2px;
  padding: 0 15px;
  border: 1.5px solid transparent;
  border-radius: 999px;
  background: var(--mv-red);
  color: var(--mv-white);
  font-weight: 700;
  line-height: 1;
  box-shadow: 0 1px 2px rgba(42, 39, 36, .10), 0 8px 18px rgba(42, 39, 36, .10);
  transition: background-color 150ms ease, border-color 150ms ease,
              color 150ms ease, transform 150ms ease;
}

@media (max-width: 1240px) {
  .mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-cta > a.elementor-item {
    margin-left: 0;
    padding: 0 11px;
  }
}
@media (max-width: 1040px) {
  .mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-cta > a.elementor-item {
    min-height: 32px;
  }
}

.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-cta > a.elementor-item:hover,
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-cta > a.elementor-item:focus {
  background: var(--mv-red-deep);
  color: var(--mv-white);
  transform: translateY(-1px);
}

.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-cta > a.elementor-item:active {
  transform: translateY(0) scale(.99);
}

.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-cta > a.elementor-item:focus-visible {
  outline: 2px solid var(--mv-focus);
  outline-offset: 3px;
}

/* On /get-involved/ itself. Section 39 marks the current page
   with a 2px red underline, which reads as a stray line across
   the bottom of a pill, so it is suppressed here and the state
   is carried by the darker fill instead. The item keeps its
   aria-current="page" and its current-menu-item class, so the
   page is still announced to a screen reader; only the drawing
   changes. (0,6,3), above both section 39's current rule and
   47-b. */
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-cta.current-menu-item > a.elementor-item,
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-cta.current-menu-ancestor > a.elementor-item {
  background: var(--mv-red-deep);
  color: var(--mv-white);
  border-bottom: 1.5px solid transparent;
}

/* --- 47-c. The pill in the burger dropdown, 899px and below --
   Section 39 gives every dropdown link display: block and
   width: 100%, which would run the fill edge to edge and read
   as a banner rather than a button. The pill is contained
   instead, and the margin keeps it clear of the hairline rules
   section 39 draws between the items above and below it. The
   dropdown is its own panel below the header, so nothing here
   can move the header row. */

.mv-nav nav.elementor-nav-menu--dropdown li.mv-nav-cta > a.elementor-item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: auto;
  min-height: 44px;
  margin-block: 12px;
  padding: 0 22px;
  border: 1.5px solid transparent;
  border-radius: 999px;
  background: var(--mv-red);
  color: var(--mv-white);
  font-weight: 700;
  line-height: 1;
  box-shadow: 0 1px 2px rgba(42, 39, 36, .10), 0 8px 18px rgba(42, 39, 36, .10);
  transition: background-color 150ms ease, border-color 150ms ease,
              color 150ms ease, transform 150ms ease;
}

.mv-nav nav.elementor-nav-menu--dropdown li.mv-nav-cta > a.elementor-item:hover,
.mv-nav nav.elementor-nav-menu--dropdown li.mv-nav-cta > a.elementor-item:focus {
  background: var(--mv-red-deep);
  color: var(--mv-white);
}

.mv-nav nav.elementor-nav-menu--dropdown li.mv-nav-cta > a.elementor-item:focus-visible {
  outline: 2px solid var(--mv-focus);
  outline-offset: 3px;
}

.mv-nav nav.elementor-nav-menu--dropdown li.mv-nav-cta.current-menu-item > a.elementor-item {
  background: var(--mv-red-deep);
  color: var(--mv-white);
}

/* The reduced motion block in section 24 names .mv-btn and the
   button widget, not this pill, so its two transforms are
   cleared here. */
@media (prefers-reduced-motion: reduce) {
  .mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-cta > a.elementor-item {
    transition: none;
  }
  .mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-cta > a.elementor-item:hover,
  .mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-cta > a.elementor-item:active {
    transform: none;
  }
  .mv-nav nav.elementor-nav-menu--dropdown li.mv-nav-cta > a.elementor-item {
    transition: none;
  }
}

/* ============================================================
   SECTION 48: the article sidebar rail
   15 September 2026 (client request, Michael, wave G, ticket G4)
   ------------------------------------------------------------
   A client change, and a deliberate divergence from the static
   build. The single article template (Theme Builder 354) lost
   its page wide featured image and gained a sidebar. The
   archive cards keep their covers; only the single article
   dropped it.

   Almost nothing here is layout. The rail vocabulary was
   already ported in sections 19 and a3: .mv-withrail is the two
   column grid (content, then a 320px column, collapsing to one
   column at 900px in section 23), .mv-rail is the stack inside
   it, .mv-rail__block is the card, .mv-rail__h is the small red
   uppercase heading. All four were measured on the live
   template before a byte was written here, and all four behave:
   724px + 320px at 1280, 48px between the columns, 24px between
   the blocks, 22px/24px inside a block. What was missing is the
   sticky itself, the treatment of editor written rich text
   inside a block, and three small component fixes.

   The blocks are Elementor containers, so the selectors below
   are written one class heavier than the component they fix,
   the same way sections a3 and a4 do it. Elementor writes its
   own declarations on .e-con and on the widget wrappers, and a
   single class here would be a coin toss on load order.

   Nothing in this section touches .mv-sharebar. The full width
   share band still exists and is still the right shape for the
   fifteen static pages that carry it. It was removed from the
   article template only, where the same controls now sit in the
   rail instead, with their data-share attributes byte for byte
   as the band carried them, so site.js module 7 still finds
   them.
   ------------------------------------------------------------ */

:root {
  /* Where the sticky rail parks. It is one gutter today, and
     not a header height, because .mv-header does NOT stick in
     this build. Measured live on 15 September 2026 at 1280: the
     header is the third child of Elementor's
     <header class="elementor-location-header"> wrapper, so that
     wrapper is its sticky containing block, the wrapper is only
     as tall as the announcement bar, the top bar and the header
     together, and the header therefore has nowhere to travel.
     Its top runs straight off the screen with the page. That is
     worth fixing in the header template, not here.
     If it is ever fixed, this is the one value to change: make
     it calc(<measured header height> + var(--mv-s4)) and the
     rail clears the header everywhere at once. */
  --mv-railstick-top: var(--mv-s4);
}

@media (min-width: 901px) {
  .mv-rail--sticky,
  .e-con.mv-rail--sticky {
    position: sticky;
    top: var(--mv-railstick-top);
    align-self: start;
    /* The rail is routinely taller than the viewport once an
       article carries both a summary and a list of sources, and
       a sticky box taller than the screen hides its own foot
       for good. So it gets its own scroll as a last resort. The
       scrollbar only appears when the content really does not
       fit, and scrolling past the end of the rail chains back
       to the page. */
    max-height: calc(100vh - var(--mv-railstick-top) - var(--mv-s4));
    overflow-y: auto;
    scrollbar-width: thin;
  }
}

/* Editor written rich text inside a block. Both sidebar fields
   are WYSIWYG, so what arrives is whatever list or paragraphs
   the editor typed. An unordered list is dressed as the site's
   own rail list from section 19, hairline separated and
   unmarked, because that is what the rail reads like everywhere
   else. A numbered list keeps its numbers, because choosing one
   is a decision about the content. */
.mv-rail__rich {
  font-size: 15px;
  line-height: 1.5;
}
.mv-rail__rich p,
.mv-rail__rich ul,
.mv-rail__rich ol {
  margin: 0;
  font-size: 15px;
  line-height: 1.5;
}
.mv-rail__rich > * + * {
  margin-top: var(--mv-s2);
}
.mv-rail__rich ul {
  list-style: none;
  padding: 0;
}
.mv-rail__rich ul > li + li {
  margin-top: var(--mv-s2);
  padding-top: var(--mv-s2);
  border-top: 1px solid var(--mv-rule);
}
.mv-rail__rich ol {
  padding-left: 1.3em;
}
.mv-rail__rich ol > li + li {
  margin-top: var(--mv-s1);
}
/* A source line is often a long URL in a short column. */
.mv-rail__rich a {
  overflow-wrap: anywhere;
}

/* Post navigation. Elementor lays previous and next side by
   side and truncates both titles to one nowrap line, which in a
   272px column leaves an ellipsis and no information. Stacked,
   full title, label above it. The separator is already off in
   the widget's own settings.

   The width, overflow and white-space below are not tidying:
   widget-post-navigation.min.css sets
   .elementor-post-navigation .elementor-post-navigation__link
   to width: calc(50% - 0.5px) with overflow hidden, text-overflow
   ellipsis and white-space nowrap, and that is what clips the
   title. Measured: without these three the link box stays 136px
   of a 272px card. The selector is written with the widget class
   in it so it outweighs Elementor's rather than tying on
   specificity and relying on load order. */
.mv-rail__nav .elementor-post-navigation {
  flex-direction: column;
  align-items: stretch;
  gap: var(--mv-s3);
}
.mv-rail__nav .elementor-post-navigation .elementor-post-navigation__link {
  flex: 0 0 auto;
  width: 100%;
  max-width: 100%;
  overflow: visible;
  text-align: left;
  text-overflow: clip;
  white-space: normal;
}
/* The first and the last article have no neighbour on one side
   and Elementor still prints the empty half. :has is the only
   way to tell the difference without JavaScript; where it is
   unsupported the row is simply empty and zero height, which is
   what happens today anyway. */
.mv-rail__nav .elementor-post-navigation .elementor-post-navigation__link:not(:has(a)) {
  display: none;
}
.mv-rail__nav .elementor-post-navigation__link a {
  display: block;
  text-decoration: none;
}
.mv-rail__nav .post-navigation__prev--label,
.mv-rail__nav .post-navigation__next--label {
  display: block;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--mv-soft);
}
.mv-rail__nav .post-navigation__prev--title,
.mv-rail__nav .post-navigation__next--title {
  display: block;
  margin-top: 4px;
  overflow: visible;
  font-size: 15px;
  font-weight: 700;
  line-height: 1.4;
  color: var(--mv-accent);
  text-overflow: clip;
  white-space: normal;
}
.mv-rail__nav .elementor-post-navigation__link a:hover .post-navigation__prev--title,
.mv-rail__nav .elementor-post-navigation__link a:hover .post-navigation__next--title {
  color: var(--mv-ink);
}
.mv-rail__nav .elementor-post-navigation__link a:focus-visible {
  outline: 2px solid var(--mv-focus);
  outline-offset: 3px;
}

/* The one button in the rail runs the full width of its block.
   A 134px pill floating in a 272px card reads as an
   afterthought. */
.mv-rail__btn.elementor-widget-button > .elementor-button {
  width: 100%;
}

/* Section 34 took the share row out of print. The controls have
   moved into the rail on articles, so the whole block goes with
   them, heading included. */
@media print {
  .mv-rail__block:has(.mv-rail__share) {
    display: none;
  }
}

/* ============================================================
   SECTION 49: the header on phones, tablets and narrow desktops
   16 September 2026 (wave H, ticket H1, blind verifier findings)
   ------------------------------------------------------------
   Three defects, all in the Theme Builder header (document
   191), all fixed here and nowhere else. Nothing in this
   section restyles the desktop menu.

   1. BELOW 900PX THE MENU WAS OUT OF REACH. Section 23's 860px
      block gives .mv-nav flex: 1 0 100%, order 3, a top rule and
      block padding. That was written for the static header row,
      which wraps, so the nav fell to a second line under the
      brand. In this build the real flex row is Elementor's
      .e-con-inner inside .mv-header__inner, which is nowrap, so
      the nav demanded a full row BESIDE the brand. Measured on
      15 and 16 September 2026 before this section: document
      width 714px at a 375px viewport, 1204px at 620, 852px at
      800, 912px at 860, with the burger drawn at x 523 to 571 at
      375, off the screen, and the header 128px tall. At 899
      section 23 is out of range but the brand block (Elementor's
      mobile --width: 100% and its own width) still pushed the
      burger to x 512 and the header to 103px.
      The fix puts the header back on one row from 0 to 899px:
      brand left, burger right. The nav widget shrinks to the
      burger, section 23's padding, rule and order are undone,
      and the brand block drops Elementor's 100% width. The
      burger's dropdown is taken out of the row and laid under
      the header, full width, as an absolute panel on
      .mv-header__inner (Elementor gives every container
      position: relative, and the nav widget and .e-con-inner
      between them are static, so that is its containing
      block). Elementor's own open and close are untouched: the
      toggle, aria-expanded, the max-height and scaleY
      transition all still run on the same element. The panel
      is padded to the page gutter so its links line up with the
      brand. Section 47-c's contained pill carries over as it is.

   2. THE HEADER DID NOT STICK. Section 22 makes .mv-header
      sticky, but the header is the third child of
      <header data-elementor-type="header"
      class="elementor elementor-191 elementor-location-header">,
      a direct child of body, and that wrapper is exactly as
      tall as the announcement bar, the top bar and the header
      together. A sticky box cannot leave its containing block,
      so the header had no travel at all. The wrapper is given
      display: contents, which removes its box and leaves its
      three children laid out as children of body, so body
      becomes the header's containing block and the header
      sticks for the length of the page while the two bars
      above it scroll away, as in the static build. Checked
      before writing: nothing in site.js, in this stylesheet or
      in Elementor's frontend reads the wrapper's box; site.js
      looks the header up by .mv-header, and descendant selectors
      such as .elementor-191 .elementor-element-... still match
      because the element is still in the tree. The rule is
      scoped to body:not(.elementor-editor-active), so inside
      the Elementor editor the wrapper keeps its box and the
      editor's own handles are not affected.
      The admin bar. When a logged in user views the site, WP
      core fixes #wpadminbar at the top, 32px tall, 46px at 782px
      and below, and at 600px and below turns it absolute so it
      scrolls away with the page. --mv-stick-offset follows
      those three states exactly, and the header, the anchor
      margin and the rail all add it. At 600px and below it is 0
      on purpose: the bar has left the screen by the time the
      header sticks.

   3. THE DESKTOP MENU WRAPPED FROM 1041PX TO 1100PX. The brand
      strapline is hidden at 1100px and below. DIVERGENCE: the
      static build hides it at 1040px (section 23). The build's
      menu carries an eighth item (Articles) and the Get
      involved pill from section 47, so it runs out of room
      60px earlier than the static menu did. Measured before:
      at 1060 the menu ran to two rows and the header was
      100.9px tall.

   THE TWO VALUES THAT ASSUMED A HEADER THAT DID NOT STICK.
   --mv-header-h is the measured height of .mv-header,
   bottom border included, rounded up to a whole pixel, in the
   three ranges where it changes. Measured on 16 September 2026
   with this section in place: 70.3px from 1101px up, 66px from
   1041 to 1100, 65px from 900 to 1040 (the ceiling 66 is used
   for both), 77px at 899 and below. From it:
   - [id] scroll-margin-top, a fixed 84px in section 22, becomes
     the header height plus 16px, so an anchor target lands one
     small gap below the stuck header.
   - --mv-railstick-top, one gutter in section 48 because the
     header did not stick, becomes the header height plus that
     same gutter, so the rail parks one gutter below the stuck
     header. Section 48's max-height calc reads the same
     variable and follows it without an edit.
   These are declared on body, not :root, so the admin bar
   offset (also set on body) is part of the value every
   descendant inherits.

   If the header's padding, the burger's size, the brand block
   or the menu ever change, measure the three heights again.
   ============================================================ */

/* --- 49-a. The sticky header's travel ------------------------ */

body:not(.elementor-editor-active) > [data-elementor-type="header"].elementor-location-header {
  display: contents;
}

body {
  --mv-stick-offset: 0px;
  --mv-header-h: 71px;
  --mv-railstick-top: calc(var(--mv-stick-offset) + var(--mv-header-h) + var(--mv-s4));
}
body.admin-bar { --mv-stick-offset: 32px; }
@media screen and (max-width: 782px) {
  body.admin-bar { --mv-stick-offset: 46px; }
}
@media screen and (max-width: 600px) {
  body.admin-bar { --mv-stick-offset: 0px; }
}
@media (max-width: 1100px) {
  body { --mv-header-h: 66px; }
}
@media (max-width: 899px) {
  body { --mv-header-h: 77px; }
}

/* (0,2,0), after section 22's (0,1,0). */
.e-con.mv-header {
  top: var(--mv-stick-offset);
}
[id] {
  scroll-margin-top: calc(var(--mv-stick-offset) + var(--mv-header-h) + 16px);
}

/* --- 49-b. The strapline, 1100px and below ------------------- */

@media (max-width: 1100px) {
  .mv-header .elementor-widget.mv-brand__sub {
    display: none;
  }
}

/* --- 49-c. One row, brand and burger, 899px and below -------- */

@media (max-width: 899px) {
  .mv-header .mv-header__inner > .e-con-inner {
    flex-wrap: nowrap;
    align-items: center;
  }
  /* Elementor's mobile rule .e-con.e-flex { --width: 100% }
     (0,2,0) is what stretched the brand link across the row. */
  .mv-header .mv-brand.e-con.e-flex {
    --width: auto;
    flex: 0 1 auto;
    min-width: 0;
  }
  /* Undoes section 23's 860px block. display: flex restates
     section 42's rule so the burger stays reachable. (0,3,0). */
  .mv-header .elementor-widget-nav-menu.mv-nav {
    position: static;
    display: flex;
    flex: 0 0 auto;
    flex-direction: row;
    align-items: center;
    order: 0;
    width: auto;
    max-width: none;
    margin-left: auto;
    padding: 0;
    border-top: 0;
  }
  /* The panel. Elementor's own rule carries margin-top: 10px
     and the open and close transition; only the placement,
     the gutter and the surface are set here. z-index 45 is
     inside the header's own stacking context (z-index 46). */
  .mv-header .mv-nav nav.elementor-nav-menu--dropdown.elementor-nav-menu__container {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 45;
    width: auto;
    margin: 0;
    padding: 0 var(--mv-pad);
    background: var(--mv-cream);
    border-top: 1px solid var(--mv-line);
    border-bottom: 1px solid var(--mv-line);
    box-shadow: 0 14px 30px rgba(42, 39, 36, .12);
  }
}

/* ============================================================
   SECTION 50: the work page timeline loses its numbers
   (22 September 2026)
   ------------------------------------------------------------
   Michael's instruction of 22 September 2026: the decimal
   markers that section 43 draws beside the 16 timeline entries
   come off. They existed only because the approved static
   page's <ol> showed the browser's default markers; on the
   built page the marker was also landing on top of the entry
   kicker, and the entries read fine without a number.

   content: none on the same selector, later in the file at the
   same specificity (0-2-0 plus the pseudo-element), removes
   the ::before box entirely. Everything else in section 43
   deliberately stands:
   - role="list" and role="listitem" stay, so a screen reader
     still announces the 16 positions. Section 43 note 4 called
     the double-read of the visual number the accepted cost of
     the ::before pattern; that cost is gone with the marker.
   - the 20px left padding stays. The cards were approved
     sitting 20px inside the container edge; taking the padding
     away would shift and widen every card, which is a layout
     change nobody asked for.
   - counter-reset and counter-increment stay written in
     section 43 but are inert with no ::before reading them.
   The mvwork counter and the mv-worklist class appear nowhere
   else in this file, no ::marker rule exists, and no
   list-style declaration reaches the wrapper, so this one
   declaration is the whole change and touches no other page.
   ============================================================ */
.e-con.mv-worklist > .e-con::before {
  content: none;
}

/* ============================================================
   SECTION 52: Standard-widget glue: header socials, search,
   hero layers, event card (T-A3, 2026-09-23)
   ============================================================
   The client edits this site himself and is never to open an
   HTML code box. Five HTML widgets and one hand-typed card were
   rebuilt from ordinary Elementor elements. The classes the old
   markup carried were kept wherever Elementor lets a class ride,
   so most of the look still comes from the sections above. This
   section only covers what Elementor's own wrapper markup breaks.
   Nothing above this point is edited. Section 46's
   .mv-herolayers rules are now inert (no element carries that
   class any more) and are left in place.

   --- 52-a. Top utility bar (header template 191) -------------
   The five social links are Elementor's Social Icons widget and
   the BM | EN switch is a Text Editor widget carrying
   p.mv-lang. Both sit in a container classed .mv-topbar__inner,
   which takes over from the old div.mv-container.mv-topbar__inner
   (1140px, 24px gutter, right-aligned, 38px tall). The widget's
   own grey squares and 25px icons are put back to section 33's
   bare white 18px icons with 6px of padding and 2px between.
   Selectors are (0,6,0) because the widget's post CSS sizes the
   icon at (0,4,0). */
.e-con.mv-topbar .e-con.mv-topbar__inner {
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: flex-end;
  gap: 20px;
  width: 100%;
  max-width: var(--mv-maxw);
  min-height: 38px;
  margin-inline: auto;
  padding-block: 0;
  padding-inline: var(--mv-pad);
}
.e-con.mv-topbar .e-con.mv-topbar__inner > .elementor-widget {
  flex: 0 0 auto;
  width: auto;
  max-width: none;
  margin: 0;
}
.e-con.mv-topbar .e-con.mv-topbar__inner .elementor-widget-social-icons {
  font-size: 0;
  line-height: 1;
}
.e-con.mv-topbar .e-con.mv-topbar__inner .elementor-social-icons-wrapper.elementor-grid {
  display: flex;
  align-items: center;
  gap: 2px;
  width: auto;
  margin: 0;
  padding: 0;
  word-spacing: normal;
}
.e-con.mv-topbar .e-con.mv-topbar__inner .elementor-social-icons-wrapper .elementor-grid-item {
  display: block;
  margin: 0;
}
.e-con.mv-topbar .e-con.mv-topbar__inner .elementor-icon.elementor-social-icon {
  --e-social-icon-icon-color: var(--mv-white);
  display: flex;
  align-items: center;
  justify-content: center;
  width: auto;
  height: auto;
  margin: 0;
  padding: 6px;
  font-size: 18px;
  line-height: 1;
  color: var(--mv-white);
  background: transparent;
  border-radius: 0;
  text-decoration: none;
}
.e-con.mv-topbar .e-con.mv-topbar__inner .elementor-icon.elementor-social-icon i,
.e-con.mv-topbar .e-con.mv-topbar__inner .elementor-icon.elementor-social-icon svg {
  display: block;
  width: 18px;
  height: 18px;
  font-size: 18px;
  line-height: 18px;
  text-align: center;
  color: var(--mv-white);
  fill: currentColor;
}
.e-con.mv-topbar .e-con.mv-topbar__inner .elementor-icon.elementor-social-icon:hover {
  opacity: .75;
  color: var(--mv-white);
}
.e-con.mv-topbar .e-con.mv-topbar__inner .elementor-widget-text-editor {
  font-size: 13px;
  line-height: 1.4;
  color: var(--mv-white);
}
/* BM is a plain span now, not a disabled button, so section
   33's [disabled] dimming is restated on aria-disabled. */
.mv-topbar .mv-lang__btn[aria-disabled="true"] {
  opacity: .8;
  cursor: not-allowed;
}
@media (max-width: 480px) {
  .e-con.mv-topbar .e-con.mv-topbar__inner .elementor-icon.elementor-social-icon { padding: 5px; font-size: 16px; }
  .e-con.mv-topbar .e-con.mv-topbar__inner .elementor-icon.elementor-social-icon i,
  .e-con.mv-topbar .e-con.mv-topbar__inner .elementor-icon.elementor-social-icon svg {
    width: 16px;
    height: 16px;
    font-size: 16px;
    line-height: 16px;
  }
}

/* --- 52-b. The two search boxes (Home, Learn) -----------------
   Elementor Pro's Search Form widget (classic skin, text button)
   inside a container classed .mv-search, with the visible label
   in a Text Editor above it (label.mv-label, pointed at the
   widget's input). The container is a column: label, then the
   form row. The form row copies section 16's layout (field grows
   from 320px, button beside it, wraps below it on a phone) and
   the field and button copy .mv-input and .mv-btn--primary. The
   widget's grey box and square grey button are removed. (0,6,0)
   so the widget's post CSS at (0,5,0) cannot win. */
.elementor.elementor .e-con.mv-search {
  flex-direction: column;
  flex-wrap: nowrap;
  align-items: stretch;
  row-gap: 6px;
  column-gap: 0;
}
.elementor.elementor .e-con.mv-search > .elementor-widget {
  width: 100%;
  margin: 0;
}
.elementor.elementor .e-con.mv-search .elementor-search-form .elementor-search-form__container {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: var(--mv-s2);
  min-height: 0;
  overflow: visible;
  background: transparent;
  border: 0;
}
.elementor.elementor .e-con.mv-search .elementor-search-form .elementor-search-form__input {
  -webkit-appearance: none;
  appearance: none;
  flex: 1 1 320px;
  min-width: 0;
  min-height: 48px;
  margin: 0;
  padding: 12px 14px;
  background: var(--mv-white);
  color: var(--mv-charcoal);
  border: 1px solid var(--mv-line-sand);
  border-radius: 8px;
  font-family: var(--mv-font);
  font-size: 16px;
  line-height: 1.4;
  transition: border-color 150ms ease;
}
.elementor.elementor .e-con.mv-search .elementor-search-form .elementor-search-form__input:hover {
  border-color: var(--mv-brown);
}
.elementor.elementor .e-con.mv-search .elementor-search-form .elementor-search-form__input:focus {
  color: var(--mv-charcoal);
}
.elementor.elementor .e-con.mv-search .elementor-search-form .elementor-search-form__input:focus-visible {
  outline: 2px solid var(--mv-focus);
  outline-offset: 2px;
}
.elementor.elementor .e-con.mv-search .elementor-search-form .elementor-search-form__submit {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  min-width: 0;
  margin: 0;
  padding: 0 26px;
  border: 1.5px solid transparent;
  border-radius: 999px;
  background: var(--mv-red);
  color: var(--mv-white);
  font-family: var(--mv-font);
  font-size: 16px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(42, 39, 36, .10), 0 8px 18px rgba(42, 39, 36, .10);
  transition: background-color 150ms ease, border-color 150ms ease,
              color 150ms ease, transform 150ms ease;
}
.elementor.elementor .e-con.mv-search .elementor-search-form .elementor-search-form__submit:hover {
  border: 1.5px solid transparent;
  border-radius: 999px;
  background: var(--mv-red-deep);
  color: var(--mv-white);
  transform: translateY(-1px);
}
.elementor.elementor .e-con.mv-search .elementor-search-form .elementor-search-form__submit:active {
  transform: translateY(0) scale(.99);
}
.elementor.elementor .e-con.mv-search .elementor-search-form .elementor-search-form__submit:focus-visible {
  outline: 2px solid var(--mv-focus);
  outline-offset: 3px;
}
@media (max-width: 620px) {
  .elementor.elementor .e-con.mv-search .elementor-search-form .elementor-search-form__submit { flex: 1 1 100%; width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .elementor.elementor .e-con.mv-search .elementor-search-form .elementor-search-form__input,
  .elementor.elementor .e-con.mv-search .elementor-search-form .elementor-search-form__submit { transition: none; }
}

/* --- 52-c. Hero decoration layers (Home, Get involved) --------
   The layers are empty containers now, not divs inside an HTML
   widget, and they sit where the widget sat: first children of
   the hero band, so sections 31 and 35 still anchor them to the
   band. Elementor gives every container position: relative, a
   width of 100%, a min height and padding, which would pull the
   layers back into the flow or, for the Get involved layers,
   override the right: var(--mv-gi-edge) inset with a full width.
   Only those properties are restated. Heights, insets, z-index
   and backgrounds stay with sections 31 and 35. */
.e-con.mv-hero__sketch,
.e-con.mv-hero__veil,
.e-con.mv-hero__fade,
.e-con.mv-hero__drawing,
.e-con.mv-hero__wash {
  position: absolute;
  width: auto;
  min-width: 0;
  max-width: none;
  min-height: 0;
  margin: 0;
  padding: 0;
  pointer-events: none;
}

/* --- 52-d. The Events card (page 53) --------------------------
   Rebuilt as a linked container (a.mv-card.mv-card--link
   .mv-eventcard) holding an Image widget and a body container
   with a heading for the date line, a heading for the title and
   two Text Editors. Section 28 lays it out as it always did. The
   container's default 20px widget gap is taken out, so the
   spacing is section 28's own margins again (10px under the
   date line and the title, 16px above "Event details"). */
.e-con.mv-eventcard {
  display: grid;
  gap: 0;
}
.e-con.mv-eventcard__body {
  gap: 0;
}

/* ============================================================
   SECTION 51: Fluent Forms, dressed as the site's own forms
   23 September 2026 (ticket T-A1)
   Numbered 51 by agreement with ticket T-A3, which appended
   section 52 first, so 51 sits after 52 in the file. Neither
   section touches the other's selectors.

   Michael's ruling: the site stops using Elementor Pro's form
   widget. Each form becomes a Fluent Forms form (free plugin),
   placed with an Elementor Shortcode widget that still carries
   mv-form on its wrapper, inside the same mv-joincard. Section
   38-b6 styles Elementor's form markup and does not reach
   Fluent Forms markup, so this section restates the same look
   against Fluent Forms' own classes: labels above in the small
   uppercase style, 48px fields on white with the sand hairline,
   the red pill submit button, and the charcoal or cream focus
   ring from --mv-focus.

   Fluent Forms loads two stylesheets of its own. The structural
   one (fluent-forms-public.css) is kept. The "default" theme
   (fluentform-public-default.css) paints blue buttons, grey
   text and a system font at (0,2,0). It is NOT switched off:
   switching it off takes a PHP filter, and no PHP is edited on
   this build. Every rule below is scoped
   `.mv-form .fluentform ...`, which is (0,3,0) or heavier, and
   so wins against that theme and against the Hello reset
   without !important.

   Error and success states. The Elementor forms showed the
   browser's own bubble for a missing email and a green-ticked
   line for success. Fluent Forms validates in the page and
   prints the message under the field, so the error line is new.
   It uses --mv-accent, which the dark band re-points to the
   light red, so it reads on the dark card as well as on sand.
   The success line keeps Elementor's look: no box, 15px, the
   ink colour, and the same green tick in front.

   Scope. Only markup inside an mv-form wrapper is touched, so a
   Fluent form placed anywhere else on the site keeps the
   plugin's own look until it is given the class.
   ============================================================ */
.mv-form .fluentform {
  font-family: var(--mv-font);
}
.mv-form .fluentform .frm-fluent-form {
  margin: 0;
}
.mv-form .fluentform .ff-el-group {
  margin: 0 0 var(--mv-s2);
  padding: 0;
}
.mv-form .fluentform .ff-el-group.ff-el-form-top .ff-el-input--label,
.mv-form .fluentform .ff-el-input--label {
  display: block;
  float: none;
  margin: 0 0 6px;
  padding: 0;
  text-align: left;
}
.mv-form .fluentform .ff-el-input--label label {
  display: block;
  margin: 0;
  font-family: var(--mv-font);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--mv-soft);
}
.mv-form .fluentform .ff-el-form-control {
  display: block;
  width: 100%;
  max-width: none;
  min-height: 48px;
  margin: 0;
  padding: 12px 14px;
  background: var(--mv-white);
  color: var(--mv-charcoal);
  border: 1px solid var(--mv-line-sand);
  border-radius: 8px;
  box-shadow: none;
  font-family: var(--mv-font);
  font-size: 16px;
  line-height: 1.4;
  transition: border-color 150ms ease;
}
.mv-form .fluentform textarea.ff-el-form-control {
  min-height: 120px;
  resize: vertical;
}
.mv-form .fluentform .ff-el-form-control:hover {
  border-color: var(--mv-brown);
}
.mv-form .fluentform .ff-el-form-control:focus,
.mv-form .fluentform .ff-el-form-control:focus-visible {
  background: var(--mv-white);
  color: var(--mv-charcoal);
  border-color: var(--mv-brown);
  outline: 2px solid var(--mv-focus);
  outline-offset: 2px;
}

/* Radio group (the media list form's "I'm signing up as").
   Measured against the Elementor radio group it replaces: one
   option per line, each line the body's own size and height
   (17px on 27.2px), the browser's radio sitting on the text
   baseline, one word space before the option text. */
.mv-form .fluentform .ff-el-form-check {
  margin: 0;
  font-size: inherit;
  line-height: inherit;
}
.mv-form .fluentform .ff-el-form-check label.ff-el-form-check-label {
  display: inline;
  margin: 0;
  font-family: var(--mv-font);
  font-size: inherit;
  font-weight: 400;
  line-height: 1;
  vertical-align: middle;
  color: var(--mv-ink);
  cursor: pointer;
}
.mv-form .fluentform .ff-el-form-check-label .ff-el-form-check-input {
  position: relative;
  top: -2px;
  display: inline-block;
  margin: 0;
  vertical-align: baseline;
}
.mv-form .fluentform .ff-el-form-check-label > span {
  display: inline;
  margin: 0;
}

/* Errors. */
.mv-form .fluentform .ff-el-is-error .ff-el-form-control {
  border-color: var(--mv-accent);
}
.mv-form .fluentform .ff-el-is-error .text-danger,
.mv-form .fluentform .error.text-danger {
  margin-top: 6px;
  font-family: var(--mv-font);
  font-size: 13px;
  line-height: 1.5;
  color: var(--mv-accent);
}
.mv-form .fluentform .ff-errors-in-stack {
  margin-top: var(--mv-s2);
  font-size: 15px;
  line-height: 1.6;
  color: var(--mv-accent);
}

/* The submit button, the site's primary button. The Elementor
   form puts 24px between the last field and the button (the
   12px grid gap plus the wrapper's 12px margin). Fluent Forms
   stacks plain blocks, so a 12px top margin here would collapse
   into the field group's 12px bottom margin and give 12px.
   Padding does not collapse, so the gap is written as padding. */
.mv-form .fluentform .ff_submit_btn_wrapper {
  margin: 0;
  padding: var(--mv-s2) 0 0;
  text-align: left;
}
.mv-form .fluentform .ff_submit_btn_wrapper .ff-btn-submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: auto;
  min-height: 48px;
  padding: 0 26px;
  border: 1.5px solid transparent;
  border-radius: 999px;
  background: var(--mv-red);
  color: var(--mv-white);
  box-shadow: 0 1px 2px rgba(42, 39, 36, .10), 0 8px 18px rgba(42, 39, 36, .10);
  font-family: var(--mv-font);
  font-size: 16px;
  font-weight: 700;
  letter-spacing: normal;
  line-height: 1;
  text-decoration: none;
  text-transform: none;
  white-space: nowrap;
  cursor: pointer;
  opacity: 1;
  transition: background-color 150ms ease, transform 150ms ease;
}
.mv-form .fluentform .ff_submit_btn_wrapper .ff-btn-submit:focus {
  background: var(--mv-red);
  color: var(--mv-white);
  border-color: transparent;
  opacity: 1;
}
.mv-form .fluentform .ff_submit_btn_wrapper .ff-btn-submit:hover {
  background: var(--mv-red-deep);
  color: var(--mv-white);
  border-color: transparent;
  opacity: 1;
  transform: translateY(-1px);
}
.mv-form .fluentform .ff_submit_btn_wrapper .ff-btn-submit:focus-visible {
  outline: 2px solid var(--mv-focus);
  outline-offset: 3px;
}
.mv-form .fluentform .ff_submit_btn_wrapper .ff-btn-submit:disabled {
  opacity: .7;
  cursor: progress;
  transform: none;
}

/* Success: Elementor's line, not Fluent Forms' boxed panel. */
.mv-form .fluentform .ff-message-success,
.mv-form .ff-message-success {
  margin: 10px 0 0;
  padding: 0;
  border: 0;
  box-shadow: none;
  font-family: var(--mv-font);
  font-size: 15px;
  line-height: 1.6;
  color: var(--mv-ink);
}
.mv-form .ff-message-success::before {
  content: "";
  display: inline-block;
  width: 1em;
  height: 1em;
  margin-inline-end: 5px;
  vertical-align: middle;
  background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNCIgaGVpZ2h0PSIxMSIgZmlsbD0ibm9uZSIgdmlld0JveD0iMCAwIDE0IDExIj48cGF0aCBmaWxsPSIjMDA4YTIwIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00Ljc1IDguMTUgMS42IDUgLjU1IDYuMDVsNC4yIDQuMiA5LTlMMTIuNy4yeiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9zdmc+") 50% / contain no-repeat;
}

@media (prefers-reduced-motion: reduce) {
  .mv-form .fluentform .ff-el-form-control,
  .mv-form .fluentform .ff_submit_btn_wrapper .ff-btn-submit { transition: none; }
  .mv-form .fluentform .ff_submit_btn_wrapper .ff-btn-submit:hover { transform: none; }
}

/* --- 52-e. Event card follow-up (T-A3, 2026-09-23, same run) ---
   Measured in a browser after 52-d went live:
   1. Elementor's `.e-con .elementor-widget.elementor-widget
      { margin-block-end: 0 }` (0,3,0) zeroes section 28's 10px
      under the date line and the title, so both are restated one
      class heavier.
   2. The date line inherited the body's computed 27.2px line
      height instead of the 1.6 ratio it had inside the old
      text-editor markup, so it stood 7px taller; the ratio is
      restated.
   3. At 620px and below, 38-a4 gives every .e-con.mv-card 20px
      side padding. The old card was a plain <a> that section 28's
      padding: 0 still reached; as a container it lost to the
      media query and the photograph and text moved 20px in from
      the border. Put back to 0. */
.e-con.mv-eventcard__body > .elementor-widget.mv-card__kicker,
.e-con.mv-eventcard__body > .elementor-widget.mv-card__title {
  margin-block-end: 10px;
}
.e-con.mv-eventcard__body > .elementor-widget.mv-card__kicker {
  line-height: 1.6;
}
@media (max-width: 620px) {
  .e-con.mv-card.mv-eventcard { padding: 0; }
}

/* ============================================================
   53. Events CPT (RUN EVT-1, 2026-09-23)
   ============================================================
   Events are now their own post type (mv_event) with ACF
   fields, drawn by four Theme Builder documents: the loop items
   "MOVE Event Card" (679) and "MOVE Event Card (stacked)"
   (681), the single "MOVE Event" (683) and the archive "MOVE
   Events Archive" (695). They carry the same classes the
   hand-built event pages carried, so sections 9, 22a, 28, 38
   and 52 still draw the cards and the page. This section adds
   only what the new structure needs. Every selector is scoped
   to a class this run introduced (mv-ev-*), so no existing
   page can change. No new colours or tokens.

   Not needed, so not written: the card excerpt kept its
   div.mv-card__body > p wrapper (a text editor with the post
   excerpt tag and a before/after wrapper), so section 28's
   .mv-eventcard .mv-card__body p rule still sets it left and
   unhyphenated. mv-ev-block and mv-ev-upcoming-only are hooks
   for the template and the automation and carry no style.
   ============================================================ */

/* --- 53-a. The listing grid. One column, 16px between cards,
   the gap the old mv-eventlist had. The widget's own gap
   controls say the same; this keeps it on the token. */
.elementor-widget-loop-grid.mv-ev-list {
  --grid-row-gap: var(--mv-s3);
  --grid-column-gap: var(--mv-s3);
}

/* --- 53-b. The facts list under "When, and who can attend".
   Label and value rows between hairlines, from type sizes the
   site already uses: the label is the 13.5px meta size, bold,
   in capitals, in the soft colour; the value is the 16.5px
   definition-list size. The rows stack under 560px. Values are
   kept ragged like other short lines (section 25 would
   otherwise justify them from 768px). */
.e-con.mv-ev-facts {
  gap: 0;
  padding: 0;
  border-bottom: 1px solid var(--mv-rule);
}
.e-con.mv-ev-fact {
  display: grid;
  grid-template-columns: minmax(0, 8.5rem) minmax(0, 1fr);
  column-gap: var(--mv-s4);
  row-gap: 2px;
  align-items: baseline;
  padding: var(--mv-s2) 0;
  border-top: 1px solid var(--mv-rule);
}
.e-con.mv-ev-fact__value {
  gap: 0;
  padding: 0;
}
.e-con.mv-ev-fact > .elementor-widget.mv-ev-fact__label > .elementor-heading-title {
  font-size: 13.5px;
  font-weight: 700;
  line-height: 1.55;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mv-soft);
}
.e-con.mv-ev-fact > .elementor-widget.mv-ev-fact__value > .elementor-heading-title,
.e-con.mv-ev-fact__value > .elementor-widget-heading > .elementor-heading-title,
.e-con.mv-ev-fact__value > .elementor-element.elementor-widget-text-editor {
  font-size: 16.5px;
  line-height: 1.55;
  text-align: left;
  -webkit-hyphens: manual;
  hyphens: manual;
}
.e-con.mv-ev-fact__value .elementor-widget-text-editor p {
  text-align: left;
  -webkit-hyphens: manual;
  hyphens: manual;
}
@media (max-width: 560px) {
  .e-con.mv-ev-fact { grid-template-columns: minmax(0, 1fr); }
}

/* --- 53-c. Plain links in the event's own text. Links saved
   with class="mv-link" are drawn by section 8 as before. A link
   the block editor or an ACF editor saves without a class, and
   the Map and Online links in the facts list, get the same look
   here. Scoped to the event page's content column. */
.e-con.mv-ev-main a:not([class]) {
  display: inline-block;
  font-weight: 700;
  font-size: 15.5px;
  color: var(--mv-accent);
  text-decoration: underline;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 4px;
  transition: color 150ms ease;
}
.e-con.mv-ev-main a:not([class]):hover { color: var(--mv-ink); }

/* ============================================================
   54. Table column widths (RUN TBL-1, 2026-10-07)
   ============================================================
   What was wrong: section 14 sets white-space: nowrap on every
   .mv-table th. That was meant for the column headings, but the
   first cell of each body row is also a th (scope="row"), so the
   row labels could not wrap either. With the browser's automatic
   table layout the longest unbreakable label then set the width
   of column 1: on the BM policy page it took 59.5% of the table,
   and on the BM Act 852 page the table grew to 1839px inside a
   1090px box and scrolled sideways on desktop.

   What this does: every .mv-table now uses a fixed layout, and
   its cells wrap normally (long words may break rather than
   push the table wider). A fixed table splits its columns
   equally unless told otherwise, so the four tables below are
   given their own ratios, tuned by measurement for the lowest
   total height in BM and EN at desktop width, with no word
   having to be broken to fit its cell at desktop width or at
   the 720px minimum. The 720px minimum width and the scrolling
   wrapper from section 14 are unchanged, so phones still scroll
   the table sideways. Row label styling (uppercase, grey,
   letter-spaced) is unchanged.

   Not keyed here: the penalties table on the retailer page
   (widget 99d8801) keeps the widths in its own colgroup
   (32/34/34) and section 32.

   To give a NEW table its own ratios: find the Elementor widget
   that holds it (the elementor-element-xxxxxxx class on the
   widget wrapper; the BM page and its EN copy share it) and
   add one rule per column on the heading row, as below. The
   percentages must add up to 100. A table with no rule here
   gets equal columns.
   ============================================================ */

.mv-table { table-layout: fixed; }
.mv-table th,
.mv-table td {
  white-space: normal;
  overflow-wrap: break-word;
}

/* The parent theme's reset gives every table a 15px bottom margin.
   Inside the bordered .mv-tablewrap that showed as an empty strip
   under the last row. The static site never had it. */
.mv-tablewrap > .mv-table { margin-block-end: 0; }

/* --- 54-a. Policy: /kedudukan-undang-undang-vape/ and /en/policy/.
   Columns: Restriction | In force since | Detail. */
.elementor-element-0a7163d .mv-table thead th:nth-child(1) { width: 24%; }
.elementor-element-0a7163d .mv-table thead th:nth-child(2) { width: 22%; }
.elementor-element-0a7163d .mv-table thead th:nth-child(3) { width: 54%; }

/* --- 54-b. Act 852: /akta-852/ and /en/act-852/.
   Columns: Instrument | What it does | Status of our check. */
.elementor-element-c23d7b1 .mv-table thead th:nth-child(1) { width: 30%; }
.elementor-element-c23d7b1 .mv-table thead th:nth-child(2) { width: 48%; }
.elementor-element-c23d7b1 .mv-table thead th:nth-child(3) { width: 22%; }

/* --- 54-c. State restrictions: /sekatan-vape-mengikut-negeri/ and
   /en/state-restrictions/. Columns: State | Since | What was done. */
.elementor-element-513ab68 .mv-table thead th:nth-child(1) { width: 20%; }
.elementor-element-513ab68 .mv-table thead th:nth-child(2) { width: 22%; }
.elementor-element-513ab68 .mv-table thead th:nth-child(3) { width: 58%; }

/* --- 54-d. Credits: /kredit/ and /en/credits/.
   Columns: Where | What it shows | Source and status. */
.elementor-element-5e17ea0 .mv-table thead th:nth-child(1) { width: 24%; }
.elementor-element-5e17ea0 .mv-table thead th:nth-child(2) { width: 30%; }
.elementor-element-5e17ea0 .mv-table thead th:nth-child(3) { width: 46%; }


/* ============================================================
   SECTION 55: source numbers, question cards, hero drawing
   (RUN FINAL-1, ticket B6, 23 October 2026)
   ------------------------------------------------------------
   Appended only. No earlier section is edited.

   55-a. Source numbers. The 01, 02, 03 numbers on .mv-sources
   lists used to hang on an empty <span class="mv-source__no">
   at the start of each .mv-source. The visual editor strips
   empty spans, so every list edited there lost its numbers.
   The number is now drawn on the .mv-source itself, with the
   same counter and the same type the span had (section 22:
   12.5px, 700, 0.14em tracking, the soft colour). As a grid
   item it takes the span's old place, first in the entry and
   one 10px grid gap above the title. Lists that still carry
   the span hide it, so no entry shows two numbers. */
.mv-source__no { display: none; }
.mv-sources > li > .mv-source::before {
  content: counter(mvsrc, decimal-leading-zero);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--mv-soft);
}

/* 55-b. Question cards in a two-column grid keep their own
   height. Grid items stretch to the row by default, so a card
   with more text pulled its neighbour down with it. */
.mv-cols-2 > .mv-qcard { align-self: start; }

/* 55-c. Home hero drawing, raised a little at 1101px and up
   (Sheep's note, "hero image position too low"). Section 31
   sets center bottom; below 1101px its own rules still apply.
   A percentage moves the drawing by that share of the space
   between band and drawing, so the lift is largest where the
   band is tallest against the drawing and shrinks to nothing
   at the width where the drawing fills the band. */
@media (min-width: 1101px) {
  .mv-hero__sketch { background-position: center 85%; }
}


/* 55-d. Home hero drawing: an even 40px lift at 1101px and up
   (RUN FINAL-1 wave 2, ticket P2, 23 October 2026). Replaces the
   value set in 55-c. A percentage lift shrinks to about 5px at
   1920 and reverses beyond it; an offset from the bottom edge
   lifts the drawing by the same 40px at every width. */
@media (min-width: 1101px) {
  .mv-hero__sketch { background-position: center bottom 40px; }
}

/* 55-e. Dashed lists inside a citation box take the box's own
   size, so the list does not render larger than the box. */
.mv-cite.mv-dash li { font-size: 14.5px; }


/* ============================================================
   SECTION 56: layout polish wave (RUN FINAL-1, ticket VX1,
   23 October 2026). Additive only: nothing above is edited.
   Each part answers one item of lead-rulings-3.md, VX1.
   ============================================================ */

/* 56-a. Get involved hero on phones. Below 741px the copy runs
   the full width over the Merdeka drawing. The wash turns
   vertical: solid cream behind the copy block, fading only
   below it, and the drawing is knocked back so no letter sits
   on a visible line. The drawing stays a background. */
@media (max-width: 740px) {
  .mv-hero--gi .mv-hero__wash {
    background: linear-gradient(180deg,
      var(--mv-bg) 0%,
      var(--mv-bg) 72%,
      rgba(250, 246, 239, 0) 100%);
  }
  .mv-hero--gi .mv-hero__drawing { opacity: .32; }
  /* The band's height follows the viewport (72vh, clamped) while
     the copy's follows the width, so on short phones the copy runs
     past 72% of the band. The copy block itself carries the cream,
     and a 40px fade under it, so the rule holds at any size. */
  .mv-hero--gi > .mv-bandinner { background-color: var(--mv-bg); }
  .mv-hero--gi > .mv-bandinner::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    height: 40px;
    background: linear-gradient(180deg, var(--mv-bg), rgba(250, 246, 239, 0));
    pointer-events: none;
  }
}

/* 56-b. Card rows. 55-b set every question card in a two-column
   grid to its own height, which also broke the equal-height rows
   on act-852 and policy. Rows stretch again; only the expanding
   question cards (the ones holding a details element, on learn)
   keep their own height. */
.mv-cols-2 > .mv-qcard { align-self: stretch; }
.mv-cols-2 > .mv-qcard:has(details) { align-self: start; }

/* 56-c. The MOVE on air tab on phones. The vertical tab sat over
   the right 30px of the content column. Below 741px it becomes a
   44px round button at the bottom right, glyph only. The button
   text stays in the markup, so its accessible name is unchanged;
   it is set at size 0 and the glyph is drawn by ::before. The
   panel is untouched. */
@media (max-width: 740px) {
  .mv-air-tab {
    top: auto;
    right: 16px;
    bottom: 16px;
    width: 44px;
    height: 44px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    transform: none;
    writing-mode: horizontal-tb;
    border-radius: 50%;
    font-size: 0;
    line-height: 0;
    letter-spacing: 0;
    box-shadow: 0 2px 10px rgba(42, 39, 36, .28);
  }
  .mv-air-tab::before {
    content: "\25B6";
    font-size: 15px;
    line-height: 1;
    padding-left: 3px;
    color: var(--mv-cream);
  }
}

/* 56-d. Ragged text in narrow boxes. Section 25 justifies the
   prose columns from 768px up, at the client's request. Cards,
   notices, three-column rows (.mv-cols-3, and .mv-beats on the
   home page), stat labels and figure labels are too narrow for it
   and open rivers, so they go back to ragged right. The prose
   measure stays justified. */
.mv-band .mv-card p,
.mv-band .mv-qcard p,
.mv-band .mv-notice p,
.mv-band .mv-cols-3 p,
.mv-band .mv-figblock p,
.mv-band .mv-pathway p,
.mv-band .mv-joincard p,
.mv-band .mv-beats p,
.mv-band .mv-stats p,
.mv-card p,
.mv-qcard p,
.mv-notice p,
.mv-cols-3 p,
.mv-figblock p,
.mv-pathway p,
.mv-joincard p {
  text-align: left;
  -webkit-hyphens: manual;
  hyphens: manual;
}

/* 56-e. A figure left alone on the last row of a figure grid
   spans the row. .mv-figures is auto-fit at 260px minimum: three
   columns from 876px, two from 584px to 875px, one below. */
@media (min-width: 876px) {
  .mv-figures > :last-child:nth-child(3n+1) { grid-column: 1 / -1; }
}
@media (min-width: 584px) and (max-width: 875.98px) {
  .mv-figures > :last-child:nth-child(2n+1) { grid-column: 1 / -1; }
}

/* 56-f. Radio and checkbox options in the Fluent forms: an 8px
   gap between the input and its label text (the word space alone
   left about 3px). */
.mv-form .fluentform .ff-el-form-check label.ff-el-form-check-label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.mv-form .fluentform .ff-el-form-check-label .ff-el-form-check-input {
  top: 0;
  flex: none;
}

/* 56-g. "Before you read on" notices. A heading widget in a notice
   rendered at the section h2 size (40px over 15px text); it takes
   the notice heading size. In the closing split bands the notice
   stretched to the form column's height and left an empty box. */
.mv-notice .elementor-element.elementor-widget-heading > .elementor-heading-title {
  font-size: 17px;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: -0.01em;
}
.mv-split > *,
.e-con.mv-split > .elementor-element { align-self: start; }

/* 56-h. Articles list cards. The card is an equal-height grid of
   two rows, and the spare height was shared with the image row,
   so the gap under the cover ran 24 to 63px. The image row now
   takes its own height and the body takes the rest. */
.e-con.mv-eventcard.mv-eventcard--stack { grid-template-rows: auto 1fr; align-content: start; }
.mv-eventcard--stack .mv-eventcard__media img {
  aspect-ratio: 3 / 2;
  object-fit: cover;
}


/* ============================================================
   SECTION 57: the Listen control on phones (RUN FINAL-1,
   ticket E3, 23 October 2026). Additive only: nothing above is
   edited. Ruling: lead-rulings-4.md, section C.
   ============================================================ */

/* Below 741px the round button of 56-c still covered the last
   20 to 24px of text lines that passed under it. The control is
   now a 28px strip fixed to the bottom edge, full width, with
   its own label centred and a hairline on top, so it stays
   distinct over the dark footer. The body gains 28px of bottom
   padding, so the last line of the page clears the strip. The button,
   its accessible name and the panel are unchanged. Between 741
   and 900px the vertical tab stays as it was. */
@media (max-width: 740px) {
  body { padding-bottom: 28px; }
  .mv-air-tab {
    top: auto;
    right: 0;
    bottom: 0;
    left: 0;
    display: block;
    width: 100%;
    height: 28px;
    padding: 0 16px;
    transform: none;
    writing-mode: horizontal-tb;
    border-radius: 0;
    border-top: 1px solid var(--mv-line-dark);
    box-shadow: none;
    font-size: 13px;
    line-height: 27px;
    letter-spacing: 0.04em;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .mv-air-tab::before { content: none; }
  .mv-air-tab:focus-visible {
    outline: 2px solid var(--mv-cream);
    outline-offset: -4px;
  }
}

/* ====================================================================
   58. Header menu flush right (RUN HDR-1, 2026-10-27)
   ==================================================================== */

/* The nav widget (.mv-nav) is a column flexbox whose cross-axis
   alignment is center. When the menu is narrower than the space
   left beside the logo, as the Malay menu is at desktop widths, the
   whole menu sits centred in that space, 26px short of the container
   edge the BM | EN selector in the top bar aligns to. The English
   menu is wider, fills the space and only looked right by chance.
   align-self: flex-end pins the menu to the right edge of the
   widget at every width. Elementor's clearfix ::after on the ul is
   also a flex item there, so it added one column-gap after the last
   button; it is not needed in a flex row. Both headers (MOVE Site
   Header and its [EN] twin) share these classes. Below 900px the
   horizontal menu is hidden behind the toggle, so nothing changes
   on phones. */
.mv-header .mv-nav > .elementor-nav-menu--main { align-self: flex-end; }
.mv-header .mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu::after { display: none; }

/* ====================================================================
   59. Sheep's final tweaks (RUN SHEEP-3, 2026-11-04)
   ==================================================================== */

/* 59-a. Sources boxes inside a note panel. Section 29's .mv-src sets
   13.5px, but the note panel's own `.mv-note p` rule (16px) is more
   specific and won, so a sources box inside the law-status panel, and
   inside every other note panel, rendered at 16px while every other
   sources box on the site is 13.5px. One size everywhere now. */
.mv-note p.mv-src { font-size: 13.5px; line-height: 1.65; }

/* 59-b. The answer-desk search on the Learn pages (Memahami vape and
   Vaping, explained) sits in a boxed container nested inside the band's
   boxed container, the only such nesting on the site, so it carried a
   second 24px gutter and started 24px to the right of the notice above
   it. The inner gutter goes; the outer one stays, so the search lines
   up with the notice and the heading at every width. */
.elementor .mv-bandinner > .e-con-inner > .e-con-boxed.mv-bandinner > .e-con-inner {
  padding-left: 0;
  padding-right: 0;
  padding-inline-start: 0;
  padding-inline-end: 0;
}

/* ====================================================================
   60. Sitewide search (RUN SEARCH-1, 2026-11-04)
   ==================================================================== */

/* 60-a. The menu item. Both menus carry a custom item classed
   mv-nav-search ("Cari" / "Search") just before the button. Before
   site.js runs it is an ordinary text item; once module 7 has wired
   it (data-mv-search) it becomes a 32px round magnifier, the label
   kept for screen readers. The Elementor pointer effect is "none" on
   this menu, so there is no underline decoration to suppress. In the
   phone dropdown the item reads as icon plus label, like a list row. */
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-search > a.elementor-item[data-mv-search] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border-radius: 999px;
  color: var(--mv-charcoal);
}
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-search > a.elementor-item[data-mv-search] .mv-navsearch__label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-search > a.elementor-item[data-mv-search]:hover,
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-search > a.elementor-item[data-mv-search]:focus-visible,
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-search > a.elementor-item[aria-expanded="true"] {
  color: var(--mv-red-deep);
  background: var(--mv-sand);
}
.mv-navsearch__icon { display: block; width: 18px; height: 18px; flex: 0 0 auto; }
.mv-nav .elementor-nav-menu--dropdown li.mv-nav-search > a[data-mv-search] {
  display: flex;
  align-items: center;
  gap: 8px;
}
.mv-nav .elementor-nav-menu--dropdown .mv-navsearch__icon { width: 16px; height: 16px; }

/* 60-b. The search band, built by site.js module 7 and appended to
   .mv-header, so it travels with the sticky header. One field and a
   button, the same sizes as the Learn page's answer-desk search,
   plus a close control. Hidden until opened. */
.mv-searchpanel { width: 100%; background: var(--mv-sand); border-top: 1px solid var(--mv-line-sand); }
.mv-searchpanel[hidden] { display: none; }
.mv-searchpanel__inner { width: 100%; max-width: var(--mv-maxw); margin-inline: auto; padding: 14px var(--mv-pad) 16px; }
.mv-searchpanel__form { display: flex; flex-wrap: wrap; align-items: center; gap: var(--mv-s2); max-width: 760px; margin: 0; }
.mv-searchpanel__input {
  -webkit-appearance: none;
  appearance: none;
  flex: 1 1 320px;
  min-width: 0;
  min-height: 48px;
  margin: 0;
  padding: 12px 14px;
  background: var(--mv-white);
  color: var(--mv-charcoal);
  border: 1px solid var(--mv-line-sand);
  border-radius: 8px;
  font-family: var(--mv-font);
  font-size: 16px;
  line-height: 1.4;
}
.mv-searchpanel__input:hover { border-color: var(--mv-brown); }
.mv-searchpanel__input:focus-visible { outline: 2px solid var(--mv-focus); outline-offset: 2px; }
.mv-searchpanel__submit {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  margin: 0;
  padding: 0 26px;
  border: 1.5px solid transparent;
  border-radius: 999px;
  background: var(--mv-red);
  color: var(--mv-white);
  font-family: var(--mv-font);
  font-size: 16px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(42, 39, 36, .10), 0 8px 18px rgba(42, 39, 36, .10);
}
.mv-searchpanel__submit:hover { background: var(--mv-red-deep); }
.mv-searchpanel__close {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--mv-brown);
  cursor: pointer;
}
.mv-searchpanel__close:hover, .mv-searchpanel__close:focus-visible { color: var(--mv-charcoal); background: var(--mv-cream); }
.mv-searchpanel__submit:focus-visible, .mv-searchpanel__close:focus-visible { outline: 2px solid var(--mv-focus); outline-offset: 2px; }

/* 60-c. Room for the icon. Before the icon the Malay row had 52px
   to spare at 1440 and the English row 10px: English labels and
   the English brand strapline are longer, so the English nav
   widget is 802px against the Malay 849px at desktop widths. The
   icon needs 32px plus a gap, so the row is compressed at every
   width the horizontal menu shows, in both languages alike: gap
   10px, type 14px and button padding 12px, where section 39 had
   18px, 14.5px and 15px. Measured with the icon, transitions off:
   English 782px in 802, Malay 773px in 849, one row, from 1041px
   up. These selectors outweigh section 39's, so its own steps at
   1240 and 1040 no longer apply; 60-d restates the 1040 one. */
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu { gap: 4px 10px; column-gap: 10px; }
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li > a.elementor-item { font-size: 14px; }
.mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-cta > a.elementor-item { padding-left: 12px; padding-right: 12px; }

/* 60-d. The last step before the burger. Elementor swaps the row
   for the burger at 899px, so the row must hold at 900, where the
   widget is 746px in both languages (the strapline is hidden by
   then). Gap 8px, type 13px, button padding 10px. At 13.5px the
   English row had 5px to spare at 900, which is less than the
   difference between two operating systems' text rendering.
   Measuring note: Elementor puts a 0.4s transition on every menu
   anchor, and in a hidden or background tab that transition never
   advances, so a computed font-size can read the OLD value for as
   long as the tab stays hidden. Measure with transitions off. */
@media (max-width: 1040px) {
  .mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu { gap: 4px 8px; column-gap: 8px; }
  .mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li > a.elementor-item { font-size: 13px; }
  .mv-nav .elementor-nav-menu--main > ul.elementor-nav-menu > li.mv-nav-cta > a.elementor-item { padding-left: 10px; padding-right: 10px; }
}

/* .hidden {display:none !important;} */