/*
Theme Name: Joe for Leader
Theme URI: https://www.joefagan.scot
Author: Joe Fagan campaign
Description: Campaign theme for Joe Fagan's Scottish Labour leadership bid. Built on the Joe Fagan MSP holding-site theme — same templates, same Patch integration — with the campaign palette, Polymath and Archivo, and the Joe for Leader lock-up. Designed to be swapped back out when the contest ends.
Version: 1.18.3
Requires at least: 6.6
Tested up to: 6.5
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: jfmsp
*/

/* ============================================================
   Design tokens
   ============================================================ */
:root {
  --paper:       #f7f3ea;  /* page background            */
  --paper-2:     #efe7d6;  /* tinted band                */
  --card:        #fffdf8;  /* raised surface             */
  --accent:      #E4003B;  /* Labour red                 */
  --accent-dark: #9a352f;  /* deep red — strap/links     */
  --ink:         #211c18;  /* headings / name            */
  --body:        #46403a;  /* paragraph text             */
  --muted:       #9a8f7c;  /* footer text                */
  --muted-2:     #a89b84;  /* eyebrows / labels          */
  --hairline:    rgba(0,0,0,.08);

  /* Map pins. Four kinds have to be told apart at 5px, so they are spread
     around the wheel from the brand colours rather than tinted off one:
     supporters carry the red, the two parliaments take the deep tones, and
     councillors the mid red. */
  --pin-member:     var(--accent);
  --pin-msp:        #1f4e79;
  --pin-mp:         #2f6b4f;
  --pin-councillor: var(--accent-dark);

  --wrap-wide:   1080px;
  --wrap-read:   760px;

  /* Corners. Two, deliberately. The hero photograph and the Get help button
     are the two the site already got right, so they become the rule: a big
     surface takes the photograph's curve, and anything you click or type into
     takes the button's. Everything in between had drifted to 4, 6, 8, 10, 12
     and 14 with no reason for any of them. */
  --r-surface:   clamp(7px, 1.4vw, 12px);
  --r-control:   3px;

  /* Bridge to the plugin's tokens.
     Patch styles itself with the block-theme variable names, so declaring them
     here makes every plugin component — router, signup, maps — inherit this
     site's palette instead of falling back to its own defaults. */
  --wp--preset--color--accent-1: var(--accent);
  --wp--preset--color--accent-3: var(--accent-dark);
}

* { box-sizing: border-box; }
html, body { margin: 0; }

body {
  background: var(--paper);
  color: var(--ink);
  font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a { color: inherit; }
img { max-width: 100%; }

/* Visually hidden but available to assistive tech (WordPress convention;
   used by the_posts_pagination's heading and the search form label). */
.screen-reader-text {
  border: 0;
  clip: rect(1px, 1px, 1px, 1px);
  clip-path: inset(50%);
  height: 1px; width: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  position: absolute !important;
  word-wrap: normal !important;
}
::selection { background: var(--accent); color: #fff; }

a:focus-visible {
  outline: 2px solid var(--accent-dark);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ============================================================
   Scaffolding
   ============================================================ */
.page { display: flex; flex-direction: column; min-height: 100vh; }

.topbar { flex: none; height: 6px; background: var(--accent); }

.wrap { width: 100%; max-width: var(--wrap-wide); margin: 0 auto; }
.wrap--read { max-width: var(--wrap-read); }

/* ------------------------------------------------------------------
   Block group wrapper flattening

   Without a theme.json, WordPress wraps every Group block's children in an
   extra <div class="wp-block-group__inner-container">. That wrapper sat
   between our flex/grid containers (.hero, .helpgrid, .contact__grid, .routes)
   and their actual columns, so the layout only ever saw one child and stacked
   everything.

   `display: contents` makes the wrapper generate no box of its own: its
   children take part in the grandparent's flex/grid directly, exactly as if
   the wrapper weren't there. One line, and every multi-column section lays out
   as designed — against the block markup as WordPress actually saves it, with
   nothing to re-paste. The wrapper carries no styling of its own, so nothing
   is lost by collapsing it. (Well supported across current browsers.)
   ------------------------------------------------------------------ */
.wp-block-group__inner-container { display: contents; }

/* Block template parts wrap their content in <div class="wp-block-template-part">.
   For the header that wrapper is only as tall as the masthead, which breaks
   position:sticky (the header sticks within the wrapper, then unsticks the moment
   you scroll past it). Collapsing the wrapper makes .site-head a direct child of
   the page container again, so it sticks against the whole scroll as before. The
   wrapper carries no styling of its own, so nothing is lost. */
.wp-block-template-part { display: contents; }

/* Those sections space their columns with `gap`; stop WordPress's default
   block-gap from also adding vertical margins to the (now hoisted) columns.
   The class-led selectors sit above core's :where() rules regardless of load
   order, and cover both the wrapped and already-flat shapes. */
.hero > *,           .hero > .wp-block-group__inner-container > *,
.helpgrid > *,       .helpgrid > .wp-block-group__inner-container > *,
.contact__grid > *,  .contact__grid > .wp-block-group__inner-container > *,
.routes > *,         .routes > .wp-block-group__inner-container > * {
  margin-block: 0;
}

/* ============================================================
   Masthead
   ============================================================ */
/* Sticky bar. The 6px red topbar sits above it and scrolls away. */
.site-head {
  position: sticky;
  top: 0;
  z-index: 30;
  flex: none;
  background: rgba(247, 243, 234, .92);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid transparent;
  transition: border-color .25s ease, box-shadow .25s ease;
}
.site-head.is-scrolled {
  border-bottom-color: var(--hairline);
  box-shadow: 0 6px 20px -16px rgba(0, 0, 0, .5);
}

/* Keep clear of the WordPress admin bar when logged in. */
body.admin-bar .site-head { top: 32px; }
@media screen and (max-width: 782px) {
  body.admin-bar .site-head { top: 46px; }
}

.masthead {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 40px;
}

/* Brand lock-ups. On the front page the Scottish Labour logo cross-fades to the
   thistle + name; elsewhere only the thistle + name is rendered. The inactive
   lock-up is hidden with `visibility` so it leaves the tab order entirely. */
/* Pin the lock-up to the left on its own, rather than relying on a right-hand
   element (the nav or region) to hold it there via space-between. With the auto
   right margin the brand stays hard left whether or not a primary menu is
   assigned, and any nav/region still lands on the right. */
.brand { flex: none; margin-right: auto; }
.brand__lock {
  display: flex;
  align-items: center;
  gap: 9px;
  text-decoration: none;
}
.brand__full img { display: block; height: 23px; width: auto; max-width: none; }

/* The thistle and the name go to different places, so they are two links.
   They still have to read as one lock-up, which is what the tight gap and the
   shared hover are for. */
.brand__thistle-link { display: flex; align-items: center; text-decoration: none; }

/* The name and the badge sit on one line of ordinary text, not in a flex row.
   A flex item that is itself a flex container has no reliable baseline — the
   browser makes one up from the box edge — which is what threw the badge out of
   line. As plain inline content the badge has a real text baseline and lands on
   the same line as "Joe Fagan" with nothing to tune. */
.brand__name-link {
  display: block;
  text-decoration: none;
  white-space: nowrap;
  line-height: 1;
}

/* The thistle is top-heavy: the flower carries about nine-tenths of the ink and
   the stem trails away thin, so centring the box floats it visually upward.
   Nudging it down by the measured offset between its ink centre and its
   geometric centre settles it against the name. Proportional, so it holds if
   the height changes. */
.brand__thistle {
  display: block;
  flex: none;
  height: 28px;
  width: auto;
  max-width: none;
  transform: translateY(6.5%);
}
.brand__name {
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 800;
  font-size: 19px;
  letter-spacing: -.01em;
  color: var(--ink);
  white-space: nowrap;
}

/* The same idea as the hero badge, shrunk: Poppins in a red box. At this size
   an x-height box would be too small to read, so it takes the cap height and
   centres against the name rather than sitting on the baseline. */
/* Sized to the F: both faces have a cap height of seven tenths of an em, so
   matching the name's size matches the capitals exactly — MSP stands the same
   height as the F and sits on the same baseline.

   line-height is the cap height rather than 1. At 1 the box takes the whole em,
   including the ascender and descender space the capitals never reach, which is
   what made it look oversized with the letters low inside it. Set to the cap
   height it closes around the letters, 1.5px clear all round. The radius keeps
   the hero's ratio to its box rather than repeating the hero's 5px. */
.brand__badge {
  display: inline-block;
  vertical-align: baseline;
  background: var(--accent);
  color: #fff;
  font-family: 'Poppins', sans-serif;
  font-weight: 700;
  font-size: 19px;
  line-height: .7;
  letter-spacing: .03em;
  padding: .12em .15em;
  margin-left: 6px;
  border-radius: .075em;
}
.brand__name-link:hover .brand__name { color: var(--accent-dark); }
.brand__thistle-link:hover { opacity: .82; }
.brand__thistle-link,
.brand__name-link { transition: opacity .18s ease; }

/* Front page: the two lock-ups stack in one box and cross-fade. */
.brand--morph { position: relative; height: 34px; min-width: 186px; }
.brand--morph .brand__lock {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  opacity: 0;
  visibility: hidden;
  transition: opacity .28s ease, visibility 0s linear .28s;
}
.brand--morph .brand__full {
  opacity: 1;
  visibility: visible;
  transition: opacity .28s ease, visibility 0s;
}
.site-head.is-scrolled .brand--morph .brand__full {
  opacity: 0;
  visibility: hidden;
  transition: opacity .28s ease, visibility 0s linear .28s;
}
.site-head.is-scrolled .brand--morph .brand__mark {
  opacity: 1;
  visibility: visible;
  transition: opacity .28s ease, visibility 0s;
}

/* Every other page: a single, ordinary link. */
.brand--fixed .brand__mark { position: static; transform: none; opacity: 1; visibility: visible; }

.masthead__region {
  font-size: 13px; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted-2); white-space: nowrap;
}
.masthead__back {
  font-size: 13px; font-weight: 600; letter-spacing: .04em;
  color: var(--muted-2); text-decoration: none;
}
.masthead__back:hover { color: var(--accent-dark); }

@media (max-width: 600px) {
  .masthead { padding: 12px 20px; }
  .brand--morph { height: 30px; min-width: 152px; }
  .brand__full img { height: 19px; }
  .brand__thistle { height: 24px; }
  .brand__name { font-size: 16px; }
  .brand__lock { gap: 9px; }
}

/* Primary navigation */
.masthead__nav { min-width: 0; }
.navlist {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 6px 22px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.navlist a {
  font-size: 14px;
  font-weight: 500;
  color: var(--body);
  text-decoration: none;
  white-space: nowrap;
}
.navlist a:hover { color: var(--accent-dark); }
.navlist .current-menu-item > a,
.navlist .current_page_item > a {
  color: var(--accent-dark);
  border-bottom: 2px solid var(--accent);
  padding-bottom: 2px;
}
@media (max-width: 600px) {
  .navlist { gap: 4px 14px; }
  .navlist a { font-size: 13px; }
}

/* ============================================================
   Hero (home)
   ============================================================ */
.hero {
  flex: 1 0 auto;
  padding: clamp(40px, 7vh, 90px) 40px 60px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(32px, 5vw, 64px);
}
.hero__text { flex: 1 1 420px; min-width: min(100%, 360px); }

.eyebrow {
  font-size: 13px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--muted-2); margin: 0 0 22px;
}

.hero__name {
  margin: 0;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 800;
  font-size: clamp(58px, 11vw, 116px);
  line-height: .9;
  letter-spacing: -0.015em;
  color: var(--ink);
}

/* MSP badge — Poppins lettering in a red box, built the same way as the one in
   the masthead so the two stay in proportion at any size.

   Drawn with ::after rather than a span in the heading: the front page is
   edited as blocks, and RichText strips inline HTML it doesn't recognise the
   moment the heading is edited. Generated content survives any edit, and the
   fallback template uses the same plain heading so one rule serves both.

   line-height is the cap height, not 1, so the box closes on the capitals
   instead of the whole em. Padding is in em, so it holds through the clamp.
   Because the cap height and Poppins' descent are both .35em either side of
   the middle, the box falls exactly the vertical padding below the baseline —
   which is all the translate has to take back to sit it on the line. */
.hero__name::after {
  content: "MSP";
  display: inline-block;
  vertical-align: baseline;
  background: var(--accent);
  color: #fff;
  font-family: 'Poppins', sans-serif;
  font-weight: 700;
  font-size: clamp(30px, 5.6vw, 59px);
  line-height: .7;
  letter-spacing: .01em;
  padding: .12em .15em;
  margin-left: 10px;
  border-radius: .075em;
  transform: translateY(-.12em);
}

.strapline {
  max-width: 680px;
  margin: 30px 0 24px;
  font-family: 'Playfair Display', Georgia, serif;
  font-style: italic;
  font-weight: 600;
  font-size: clamp(22px, 3.6vw, 32px);
  line-height: 1.35;
  color: var(--accent-dark);
}

.welcome {
  max-width: 640px;
  margin: 0;
  font-size: clamp(16px, 1.6vw, 18px);
  line-height: 1.72;
  color: var(--body);
}

/* Portraits are <figure> elements now (the image block's shape; the fallback
   template matches it), so layout lives on the figure and the photo treatment
   on the img. Explicit margins override the browser's figure defaults. */

/* Portrait — desktop column.

   These carry a .hero prefix on purpose. On the block-built front page the
   portraits render as <figure class="wp-block-image">, and the block-library
   stylesheet's .wp-block-image rules share the same specificity as a bare
   .hero__photo-* class but load later — so they were quietly winning, which
   put the mobile photo on screen at desktop widths and knocked the desktop
   photo out of its flex column. Scoping under .hero lifts every one of these
   above block-library and settles the cascade regardless of load order. */
.hero .hero__photo-desktop {
  display: block;
  flex: 1 1 300px;
  min-width: min(100%, 280px);
  max-width: 420px;
  margin: 0;
}
.hero .hero__photo-desktop img {
  width: 100%;
  height: auto;
  display: block;
  object-fit: cover;
  object-position: 50% 6%;
  border-radius: var(--r-surface);
  box-shadow: 0 18px 44px -18px rgba(0,0,0,.4);
}

/* Portrait — mobile, sits inside the text column under the strapline */
.hero .hero__photo-mobile {
  display: none;
  width: 100%;
  margin: 0 0 28px;
}
.hero .hero__photo-mobile img {
  display: block;
  width: 100%;
  height: clamp(200px, 52vw, 300px);
  object-fit: cover;
  object-position: center 6%;
  border-radius: 12px;
  box-shadow: 0 14px 36px -16px rgba(0,0,0,.4);
}

@media (max-width: 760px) {
  .hero .hero__photo-desktop { display: none; }
  .hero .hero__photo-mobile  { display: block; }
}

/* Site-wide 20px mobile gutter: the masthead, bands, and footer all drop from
   40px to 20px at 600px, so the hero and contact grid follow suit. */
@media (max-width: 600px) {
  .hero {
    padding-left: 20px;
    padding-right: 20px;
  }
  .contact__grid {
    padding-left: 20px;
    padding-right: 20px;
  }
}

/* On narrow phones the logo keeps its true size; the region label gives way:
   it shrinks a touch and may wrap to a second line rather than squeezing the logo. */
@media (max-width: 480px) {
  .masthead__region {
    font-size: 12px;
    letter-spacing: .06em;
    white-space: normal;
    text-align: right;
  }
}

/* ============================================================
   Contact bar
   ============================================================ */
.contact { flex: none; background: var(--accent); color: #fff; }
.contact__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 32px;
  padding: 40px;
}
.contact__label {
  font-size: 11px; font-weight: 700;
  letter-spacing: .15em; text-transform: uppercase;
  opacity: .72; margin: 0 0 10px;
}
.contact__email,
.contact__emailline a {
  font-size: 16px; line-height: 1.5; font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid rgba(255,255,255,.4);
  padding-bottom: 2px;
}
.contact__emailline { margin: 0; }
.contact__address { font-size: 16px; line-height: 1.6; margin: 0; }
.contact__social { display: flex; gap: 18px; font-size: 15px; font-weight: 600; }
.contact__social p { margin: 0; }
.contact__social a {
  text-decoration: none;
  border-bottom: 1px solid rgba(255,255,255,.4);
  padding-bottom: 2px;
}
.contact__handle { font-size: 14px; opacity: .85; margin: 8px 0 0; }
.contact a:hover { border-bottom-color: #fff; }

/* ============================================================
   News (front-page band, listing, archives, single)
   ============================================================ */
.band--news { background: var(--paper-2); }

.newsgrid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  margin-top: 8px;
}
@media (max-width: 860px) { .newsgrid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .newsgrid { grid-template-columns: 1fr; } }

/* On the listing/archive pages the grid lives inside .doc, whose children are
   capped to the reading measure — the cards want the full column instead. */
.doc .newsgrid,
.doc .news-pagination { max-width: none; }

.news-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--hairline);
  border-radius: 14px;
  overflow: hidden;
}
.news-card__media { display: block; }
.news-card__img { display: block; width: 100%; height: 180px; object-fit: cover; }
.news-card__body { padding: 18px 20px 22px; display: flex; flex-direction: column; gap: 8px; }
.news-card__meta {
  margin: 0;
  font-size: 12px; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted-2);
}
.news-card__title {
  margin: 0;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700; font-size: 20px; line-height: 1.2;
  color: var(--ink);
}
.news-card__title a { text-decoration: none; color: inherit; }
/* Stretch the title link across the whole card so the card is clickable. */
.news-card__title a::after { content: ""; position: absolute; inset: 0; }
.news-card:hover .news-card__title { color: var(--accent-dark); }
.news-card__excerpt { margin: 0; font-size: 14.5px; line-height: 1.6; color: var(--body); }

.news-more { margin: 28px 0 0; }
.news-more a {
  font-size: 15px; font-weight: 600; color: var(--accent-dark);
  text-decoration: none; border-bottom: 1px solid currentColor; padding-bottom: 1px;
}
.news-more a:hover { color: var(--accent); }

.news-empty { color: var(--muted); }

/* The front page's "Latest" row is a core Query Loop given the class
   .news-cards. Its featured-image block declares 16/9 but does not force the
   image to the column width, so a smaller-resolution picture renders narrower —
   and therefore shorter — than the others. Pin every card image to the full
   column at 16/9 with a cover crop so the three photos match. Scoped to
   .news-cards so nothing else that uses a featured image is affected. */
.news-cards .wp-block-post-featured-image { margin: 0; }
.news-cards .wp-block-post-featured-image img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  height: auto;
  object-fit: cover;
}

/* Single post extras layered onto the .doc / .privacy-body column */
.news-chips { margin: 0 0 22px; display: flex; flex-wrap: wrap; gap: 8px; }
.news-chip {
  font-size: 12px; font-weight: 600; letter-spacing: .03em;
  color: var(--accent-dark);
  background: rgba(228, 0, 59, .08);
  border-radius: 999px; padding: 4px 12px; text-decoration: none;
}
.news-chip:hover { background: rgba(228, 0, 59, .15); }
.news-single__media { margin: 0 0 26px; }
.news-single__img { width: 100%; border-radius: 14px; display: block; }
.news-back { margin-top: 44px; }
.news-back a { font-size: 15px; font-weight: 600; color: var(--accent-dark); text-decoration: none; }
.news-back a:hover { color: var(--accent); }

/* Pagination — shared by the shortcode (paginate_links) and the archive
   templates (the_posts_pagination). */
.news-pagination { margin: 32px 0 0; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.news-pagination .nav-links,
.news-pagination.nav-links { display: flex; gap: 6px; flex-wrap: wrap; }
.news-pagination .page-numbers {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 40px; height: 40px; padding: 0 10px;
  border: 1px solid var(--hairline); border-radius: 10px;
  text-decoration: none; font-size: 14px; font-weight: 600; color: var(--ink);
}
.news-pagination .page-numbers.current { background: var(--ink); color: #fff; border-color: var(--ink); }
.news-pagination .page-numbers:hover:not(.current) { border-color: var(--accent); color: var(--accent-dark); }
.news-pagination .page-numbers.dots { border-color: transparent; }

/* ============================================================
   Footer
   ============================================================ */
.sitefoot {
  background: var(--ink);
  color: #cfc6b6;
  margin-top: 0;
}
.sitefoot a { color: #f0e9dc; text-decoration: none; }
.sitefoot a:hover { color: #fff; text-decoration: underline; }

/* The footer containers are bare .wrap elements, so — unlike the bands and
   masthead, which pad themselves — they must carry their own side gutters. */
.sitefoot__cols,
.sitefoot__legalbar {
  padding-left: 40px;
  padding-right: 40px;
}

.sitefoot__cols {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr;
  gap: 40px;
  padding-top: 54px;
  padding-bottom: 40px;
}
.sitefoot__name {
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 800; font-size: 21px;
  color: #fff; margin: 0 0 8px;
}
.sitefoot__blurb { margin: 0; max-width: 32ch; font-size: 14px; line-height: 1.6; }
.sitefoot__h {
  font-size: 12px; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted-2); margin: 0 0 12px;
}
.sitefoot__col { font-size: 15px; line-height: 1.9; }
.sitefoot__addr { font-size: 14px; line-height: 1.6; display: inline-block; margin-top: 6px; }
.sitefoot__handle { font-size: 14px; color: var(--muted-2); margin: 10px 0 0; }

.sitefoot__legalbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  padding-top: 18px; padding-bottom: 26px;
  border-top: 1px solid rgba(255,255,255,.12);
}
.sitefoot__copy { font-size: 13px; color: var(--muted-2); }
.sitefoot__link { font-size: 13px; }

@media (max-width: 780px) {
  .sitefoot__cols { grid-template-columns: 1fr; gap: 28px; padding-top: 40px; }
}
@media (max-width: 600px) {
  .sitefoot__cols,
  .sitefoot__legalbar {
    padding-left: 20px;
    padding-right: 20px;
  }
}

/* ============================================================
   Privacy notice
   ============================================================ */
.doc { flex: 1 0 auto; padding: 48px 40px 80px; }
@media (max-width: 600px) {
  .doc { padding-left: 20px; padding-right: 20px; }
}

/* The document column matches the home page width so headings line up,
   but the text itself stays at a comfortable reading measure, left-aligned. */
.doc > * { max-width: var(--wrap-read); }

/* Plugin blocks set to full width need the whole column, but the page's prose
   must keep its reading measure. So the content wrapper is uncapped only on
   pages that actually contain a full-width block, and its other children are
   capped individually instead. */
.doc > .privacy-body:has(.patch-cb--full),
.doc > .bio-body:has(.patch-cb--full) { max-width: none; }
.privacy-body:has(.patch-cb--full) > :not(.patch-cb--full),
.bio-body:has(.patch-cb--full) > :not(.patch-cb--full) { max-width: var(--wrap-read); }
.patch-cb--full { max-width: none; width: 100%; }

.doc__kicker {
  font-size: 12px; font-weight: 700;
  letter-spacing: .15em; text-transform: uppercase;
  color: var(--muted-2); margin: 0 0 16px;
}
.doc__title {
  margin: 0 0 14px;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 800;
  font-size: clamp(42px, 7vw, 62px);
  line-height: 1;
  letter-spacing: -0.01em;
}
.doc__updated { font-size: 14px; color: var(--muted); margin: 0 0 28px; }
.doc__intro { font-size: 17px; line-height: 1.72; color: var(--body); margin: 0 0 14px; }
.doc__draft-flag {
  margin: 0 0 40px;
  padding: 12px 14px;
  font-size: 13px; line-height: 1.5; font-weight: 600;
  color: var(--accent-dark);
  background: #f6e6e3;
  border: 1px solid #ecccc6;
  border-radius: 8px;
}

/* Body region — styles both the bundled draft and any wording the
   office later pastes into the WordPress page editor. */
.privacy-body > *:first-child { margin-top: 0; }
.privacy-body h2 {
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700; font-size: 25px; line-height: 1.2;
  margin: 34px 0 12px; color: var(--ink);
}
.privacy-body p {
  font-size: 16px; line-height: 1.72; color: var(--body); margin: 0 0 16px;
}
.privacy-body p:last-child { margin-bottom: 0; }

.privacy-body h3 {
  font-family: 'Poppins', sans-serif;
  font-weight: 600;
  font-size: 16px;
  line-height: 1.4;
  margin: 24px 0 6px;
  color: var(--ink);
}
.privacy-body ul {
  margin: 0 0 16px;
  padding-left: 1.25em;
}
.privacy-body li {
  font-size: 16px;
  line-height: 1.72;
  color: var(--body);
  margin: 0 0 8px;
}
.privacy-body li::marker { color: var(--accent); }
.privacy-body li:last-child { margin-bottom: 0; }
.privacy-body a {
  color: var(--accent-dark);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.privacy-body a:hover { color: var(--accent); }
.privacy-body strong { font-weight: 600; color: var(--ink); }
.privacy-body .contact-block {
  font-size: 16px; line-height: 1.85; color: var(--body); margin: 0 0 16px;
}

.welcome-more { margin: 18px 0 0; }
.welcome-more a {
  font-size: 15px; font-weight: 600; color: var(--accent-dark);
  text-decoration: none; border-bottom: 1px solid currentColor; padding-bottom: 1px;
}
.welcome-more a:hover { color: var(--accent); }

/* ============================================================
   Bio page
   ============================================================ */
.bio-hero {
  display: flex;
  flex-direction: row-reverse;   /* portrait is first in DOM -> sits on the right */
  flex-wrap: wrap;
  align-items: flex-start;
  gap: clamp(24px, 3.5vw, 40px);
  margin: 0 0 38px;
}
.bio-hero__portrait { flex: 0 0 230px; max-width: 230px; }
.bio-hero__portrait img {
  width: 100%; height: auto; display: block;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: 12px;
  box-shadow: 0 14px 34px -18px rgba(0,0,0,.45);
}
.bio-hero__intro { flex: 1 1 320px; min-width: min(100%, 280px); }
.bio-hero__intro p {
  font-size: 17px; line-height: 1.7; color: var(--body); margin: 0 0 16px;
}
.bio-hero__intro p:last-child { margin-bottom: 0; }

/* Narrow screens: portrait becomes a full-width, wide band sitting directly
   below the title, cropped to Joe's face rather than the square desktop crop.
   Tweak object-position's Y value to reframe the face, or aspect-ratio for a
   taller/shorter band. */
@media (max-width: 620px) {
  .bio-hero { flex-direction: column; align-items: stretch; }
  .bio-hero__portrait { flex: none; width: 100%; max-width: none; margin: 0; }
  .bio-hero__portrait img { aspect-ratio: 16 / 9; object-position: 50% 20%; }
  .bio-hero__intro { width: 100%; }
}

/* Key facts */
.bio-facts { margin: 0 0 38px; padding: 0; border-top: 1px solid var(--hairline); }
.bio-facts div {
  display: flex; flex-wrap: wrap; gap: 3px 18px;
  padding: 11px 0; border-bottom: 1px solid var(--hairline);
}
.bio-facts dt {
  flex: none; width: 132px; padding-top: 3px;
  font-size: 11px; font-weight: 700; letter-spacing: .13em;
  text-transform: uppercase; color: var(--muted-2);
}
.bio-facts dd {
  flex: 1 1 220px; margin: 0;
  font-size: 15.5px; line-height: 1.55; font-weight: 500; color: var(--ink);
}

/* Full-width photo band inside the bio */
.bio-figure { margin: 28px 0 30px; }
.bio-figure img {
  width: 100%; height: auto; display: block;
  border-radius: 12px;
  box-shadow: 0 16px 40px -20px rgba(0,0,0,.45);
}
.bio-figure figcaption {
  font-size: 13px; line-height: 1.5; color: var(--muted); margin: 10px 0 0;
}

/* Bio prose */
.bio-body h2 {
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700; font-size: 25px; line-height: 1.2;
  margin: 34px 0 12px; color: var(--ink);
}
.bio-body h2:first-child { margin-top: 0; }
.bio-body p { font-size: 16px; line-height: 1.72; color: var(--body); margin: 0 0 16px; }
.bio-body p:last-child { margin-bottom: 0; }
.bio-body em { font-style: italic; }

/* Closing contact prompt */
.bio-cta {
  margin: 44px 0 0; padding: 22px 24px;
  background: var(--paper-2); border-radius: 12px;
}
.bio-cta p { margin: 0; font-size: 15.5px; line-height: 1.65; color: var(--body); }
.bio-cta a {
  font-weight: 600; color: var(--accent-dark);
  text-decoration: underline; text-underline-offset: 2px;
}

/* Footer may carry more than one link */
.sitefoot__links { display: flex; gap: 20px; flex-wrap: wrap; }

/* ============================================================
   Motion preference
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ---------------------------------------------------------------------------
   Front page bands (plugin-backed sections)
   --------------------------------------------------------------------------- */

.band { padding: 68px 0; border-top: 1px solid var(--hairline); }
.band .wrap { padding-left: 40px; padding-right: 40px; }

.band__head { max-width: var(--wrap-read); margin-bottom: 32px; }
.band__kicker {
  font-size: 12px; font-weight: 600;
  letter-spacing: .15em; text-transform: uppercase;
  color: var(--muted); margin: 0 0 10px;
}
.band__title {
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 800; font-size: clamp(26px, 3.4vw, 38px);
  line-height: 1.15; letter-spacing: -.01em;
  color: var(--ink); margin: 0 0 12px;
}
.band__lede { font-size: 17px; line-height: 1.65; color: var(--body); margin: 0; max-width: 54ch; }

/* Get help */
.band--help { background: var(--paper); }
.band--help .band__body { max-width: 760px; }

/* Signup: a full-width band so it reads as a distinct invitation */
.band--signup { background: var(--paper-2); }
.band--signup__inner { display: flex; justify-content: flex-start; }

@media (max-width: 600px) {
  .band { padding: 48px 0; }
  .band .wrap { padding-left: 20px; padding-right: 20px; }
  .band__head { margin-bottom: 24px; }
}

/* Plugin components sit inside theme bands — align their shape with the site. */
.band .lir-router__panel,
.band .lir-teaser {
  font-family: inherit;
}
.band .lir-teaser__h {
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 800;
  font-size: clamp(24px, 3vw, 32px);
  line-height: 1.15;
  letter-spacing: -.01em;
  color: var(--ink);
}
.band .lir-teaser__t { color: var(--body); font-size: 16px; }
.band .lir-router__panel {
  background: var(--card, #fffdf8);
  border-color: var(--hairline);
  border-radius: 12px;
}

/* ---------------------------------------------------------------------------
   Get help section
   --------------------------------------------------------------------------- */

.helpgrid {
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  gap: 44px;
  align-items: center;
}
.helpgrid__intro .band__lede { margin-bottom: 0; }

.routes { display: flex; flex-direction: column; gap: 12px; }

.route {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  background: var(--card);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 16px 18px;
}
/* The coloured dot is generated content, not markup, for the same reason as
   the hero badge: the cards are editable blocks, and a span would not survive
   an edit. Only the three explainer cards get one — no content, no dot. */
.route--msp::before,
.route--mp::before,
.route--council::before {
  content: "";
  flex: none;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  margin-top: 6px;
}
.route--msp::before     { background: var(--accent); }
.route--mp::before      { background: #2f5d9a; }
.route--council::before { background: #6a8a3a; }
.route__title {
  margin: 0 0 2px;
  font-family: Poppins, system-ui, sans-serif;
  font-size: 15px; font-weight: 600;
  color: var(--ink);
}
.route__desc { margin: 0; font-size: 13.5px; line-height: 1.55; color: var(--muted); }

/* The fourth box: the one that does something, so it carries the weight. */
.route--start {
  background: var(--ink);
  border-color: var(--ink);
  padding: 18px;
}
.route--start .route__startbody { width: 100%; }
.route--start .route__title { color: #fff; font-size: 16px; margin-bottom: 4px; }
.route--start .route__desc { color: #cfc6b6; margin-bottom: 12px; }

/* The router's inline row, inside the dark card. */
.route--start .lir-router__start { gap: 8px; }
.route--start .lir-router__start input[type="text"] {
  flex: 1 1 140px;
  padding: 12px 14px;
  font-size: 15px;
  border-color: transparent;
}
.route--start .lir-router__start .lir-btn { padding: 12px 20px; font-size: 15px; }
.route--start .lir-router__err { color: #ffb3c4; margin-top: 8px; }

/* Nothing expands in place: the card only ever holds the postcode box, and
   the check itself continues on the Get help page. */

.jfmsp-admin-note {
  background: #fcf6e6;
  border: 1px solid #e6d9a8;
  border-radius: 8px;
  padding: 12px 16px;
  margin-bottom: 24px;
  font-size: 14px;
  line-height: 1.55;
}

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

/* Wins band */
.band--wins { background: var(--paper-2); }
.band--wins .lir-win__title {
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  color: var(--ink);
}

/* ============================================================
   Patch — endorsements (form, list, map) and the deletion form

   These live here rather than in the plugin's form.css so they survive
   Patch updates. The plugin scopes its field styling to .lir-app, which
   none of these roots match, so the base rules are restated for
   .lir-endorse / .lir-scrub and then themed with the site's tokens.
   ============================================================ */

.lir-endorse *,
.lir-scrub * { box-sizing: border-box; }

.lir-endorse label,
.lir-scrub label {
  display: block;
  font-weight: 500;
  margin: 14px 0 6px;
  color: var(--ink);
}
.lir-endorse input[type="text"],
.lir-endorse input[type="email"],
.lir-endorse input[type="tel"],
.lir-endorse input[type="file"],
.lir-endorse select,
.lir-endorse textarea,
.lir-scrub input[type="text"],
.lir-scrub input[type="email"] {
  width: 100%;
  padding: 11px 13px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-control);
  font: inherit;
  font-size: 16px;           /* 16px stops iOS zooming the field on focus */
  background: #fff;
  color: var(--ink);
}
.lir-endorse textarea { min-height: 140px; resize: vertical; }

/* A select does not inherit the inputs' look on its own: it keeps the
   browser's own control unless the native appearance is removed, which is why
   it sat out of place next to the text fields. */
.lir-endorse select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 38px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%2346403a' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  cursor: pointer;
}
.lir-endorse input:focus-visible,
.lir-endorse textarea:focus-visible,
.lir-scrub input:focus-visible {
  outline: 2px solid var(--accent-dark);
  outline-offset: 2px;
  border-color: transparent;
}

.lir-endorse__form > p,
.lir-scrub__form > p { margin: 0 0 4px; }

/* The photo hint is a <span> JS writes into. Empty most of the time, so
   it must collapse rather than reserve a line. */
span.lir-hint { display: block; margin: 6px 0 0; font-size: 14px; color: var(--muted); }
span.lir-hint:empty { display: none; }

/* Consent — two separate decisions, two deliberate blocks. Never merged,
   never shrunk to small print. The label returns to a flex row so the tick
   sits beside its text. */
.lir-consent { margin: 16px 0 0; }
.lir-consent label {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 0;
  padding: 15px 17px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-control);
  background: var(--card);
  font-weight: 400;
  font-size: 15.5px;
  line-height: 1.55;
  color: var(--body);
  cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease;
}
.lir-consent label:hover { border-color: var(--accent); background: #fff; }
.lir-consent input[type="checkbox"] {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  margin: 1px 0 0;
  accent-color: var(--accent);
}
.lir-consent + .lir-consent { margin-top: 10px; }

.lir-endorse__form .lir-btn,
.lir-scrub .lir-btn { margin-top: 10px; }

.lir-endorse__msg:empty,
.lir-scrub__msg:empty { display: none; }
.lir-endorse__msg,
.lir-scrub__msg { margin: 12px 0 0; font-size: 15px; color: var(--body); }

/* Replaces the whole form on success — without this the form just looks
   like it vanished. */
.lir-endorse__done,
.lir-scrub__done {
  margin: 0;
  padding: 22px 24px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-surface);
  background: var(--paper-2);
  font-size: 17px;
  line-height: 1.6;
  color: var(--ink);
}

/* ---- Endorsements list ---- */

.lir-endorsements__group {
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: 22px;
  line-height: 1.2;
  margin: 34px 0 14px;
  color: var(--ink);
}
.lir-endorsements__group:first-child { margin-top: 0; }

.lir-endorsements {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 16px;
}

.lir-endorsement {
  display: grid;
  grid-template-columns: 96px 1fr;
  gap: 20px;
  align-items: start;
  padding: 22px;
  border: 1px solid var(--hairline);
  border-radius: 14px;
  background: var(--card);
}
/* No photo, logo or initials — close the empty column. */
.lir-endorsement:not(:has(.lir-endorsement__photo)):not(:has(.lir-endorsement__logo)):not(:has(.lir-endorsement__mark)) {
  grid-template-columns: 1fr;
}

.lir-endorsement__photo,
.lir-endorsement__logo,
.lir-endorsement__mark {
  grid-column: 1;
  width: 96px;
  height: 96px;
  border-radius: 10px;
}
.lir-endorsement__photo { object-fit: cover; }
/* A logo is artwork, not a portrait — contain it, don't crop. */
.lir-endorsement__logo { object-fit: contain; background: #fff; padding: 8px; border: 1px solid var(--hairline); }
/* Typographic stand-in when an organisation has no logo: same footprint
   as a logo, initials in the site's display face. */
.lir-endorsement__mark {
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(228, 0, 59, .08);
  color: var(--accent-dark);
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: 26px;
  letter-spacing: .02em;
  line-height: 1;
}

.lir-endorsement__words {
  grid-column: 2;
  margin: 0;
  padding: 0;
  border: 0;
  font-family: 'Playfair Display', Georgia, serif;
  font-size: 18px;
  line-height: 1.6;
  color: var(--ink);
}
.lir-endorsement__words:empty { display: none; }

.lir-endorsement__who {
  grid-column: 2;
  margin: 12px 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 12px;
  font-size: 14.5px;
}
/* Office-added organisation records often have no words. */
.lir-endorsement__words:empty + .lir-endorsement__who { margin-top: 0; }

.lir-endorsement__name { font-weight: 600; color: var(--ink); }
.lir-endorsement__role,
.lir-endorsement__town { color: var(--muted); }
.lir-endorsement__role:empty,
.lir-endorsement__town:empty { display: none; }

@media (max-width: 480px) {
  .lir-endorsement { grid-template-columns: 64px 1fr; gap: 16px; padding: 18px; }
  .lir-endorsement__photo,
  .lir-endorsement__logo,
  .lir-endorsement__mark { width: 64px; height: 64px; }
  .lir-endorsement__mark { font-size: 18px; }
  .lir-endorsement__words { font-size: 16.5px; }
}

/* ---- Endorser map ---- */

/* Leaflet renders nothing without an explicit height, and Scotland is
   tall and narrow, so the map wants height rather than width. */
.lir-endorse-map {
  min-height: 560px;
  border: 1px solid var(--hairline);
  border-radius: 12px;
  overflow: hidden;
}
@media (max-width: 782px) {
  .lir-endorse-map { min-height: 380px; }
}

.lir-endorse-map .leaflet-popup-content {
  margin: 12px 14px;
  font-family: 'Poppins', sans-serif;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--body);
}
.lir-endorse-map .leaflet-popup-content p { margin: 0 0 4px; }
.lir-endorse-map .leaflet-popup-content p:last-child { margin-bottom: 0; }
/* Pin fill comes from the plugin's accent setting via JS; this only adds
   an outline so pins read against both land and sea. */
.lir-endorse-map .leaflet-interactive { stroke: #fff; stroke-width: 1.5; }

/* ---- Side-by-side layout ----
   The form and map are separate blocks with headings between them, so
   there is no plugin wrapper to lay out. Wrap them in a Group with the
   class lir-endorse-layout for the 2:1 split; below 783px it stacks in
   source order, form first. */
@media (min-width: 783px) {
  .lir-endorse-layout {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: 40px;
    align-items: start;
  }
}

/* ============================================================
   Patch — endorsement map, tally, and endorser cards

   The map is a flat SVG drawn from boundaries uploaded in the
   plugin. There is no tile layer, so the land, outlines, and pins
   all take the site's own colours.
   ============================================================ */

.lir-map__tally { display: flex; gap: 22px; flex-wrap: wrap; margin: 0 0 14px; }
.lir-map__stat { flex: 1 1 90px; }
.lir-map__stat b {
  display: block;
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 800; font-size: 30px; line-height: 1;
  color: var(--ink);
}
.lir-map__stat span {
  font-size: 12px; font-weight: 600; letter-spacing: .05em;
  text-transform: uppercase; color: var(--muted-2);
}

.lir-map__bar {
  height: 7px; border-radius: 99px;
  background: var(--paper-2); overflow: hidden; margin: 0 0 6px;
}
.lir-map__bar i { display: block; height: 100%; background: var(--accent); }
.lir-map__barlab { font-size: 13px; color: var(--muted); margin: 0 0 18px; }

.lir-map__frame {
  position: relative;
  background: #f3efe5;
  border: 1px solid var(--hairline);
  border-radius: 12px;
  overflow: hidden;
}
/* The map is taller than it is wide, so a plain width:100% makes it far taller
   than the screen. Capping the height lets the SVG letterbox itself within the
   frame instead — it never exceeds the viewport, whatever the shape of the
   uploaded areas. */
.lir-map__svg {
  display: block;
  width: 100%;
  height: auto;
  max-height: min(78vh, 720px);
  margin: 0 auto;
}

.lir-map__area {
  fill: #e7ddc9;
  stroke: #cdbfa4;
  stroke-width: .6;
  stroke-linejoin: round;
}
/* An area that has nominated. */
.lir-map__area.is-on {
  fill-opacity: .22;
  stroke: var(--accent);
  stroke-width: .9;
  cursor: pointer;
  transition: fill-opacity .18s ease;
}
.lir-map__area.is-on:hover,
.lir-map__area.is-on:focus { fill-opacity: .4; outline: none; }

/* Each kind its own colour: a map of thirty identical dots says only that
   thirty people exist. Declared as tokens so the key and the pins cannot
   drift apart. */
.lir-map__pin { cursor: pointer; outline: none; }

/* The tokens are handed to the plugin's own, which is what its map key reads.
   Setting the fills here instead coloured the pins but left the key on the
   plugin's defaults — members drew red on the map and grey in the key, the
   drift these tokens exist to prevent. The plugin colours dots, halos and
   shading from these, so only the strokes are ours. */
.lir-map {
  --lir-pin-member:     var(--pin-member);
  --lir-pin-msp:        var(--pin-msp);
  --lir-pin-mp:         var(--pin-mp);
  --lir-pin-councillor: var(--pin-councillor);
  --lir-area-on:        var(--accent);
}
.lir-map__halo { opacity: 0; transition: opacity .18s ease; }
.lir-map__dot  { stroke: #fff; stroke-width: 1.5; }
.lir-map__pin--mp .lir-map__dot,
.lir-map__pin--msp .lir-map__dot,
.lir-map__pin--councillor .lir-map__dot { stroke-width: 1.2; }
.lir-map__pin:hover .lir-map__halo,
.lir-map__pin:focus .lir-map__halo { opacity: .22; }
.lir-map__pin:focus .lir-map__dot { stroke: var(--ink); stroke-width: 1.6; }

.lir-map__tip {
  position: absolute;
  pointer-events: none;
  background: var(--card);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  padding: 10px 12px;
  box-shadow: 0 12px 30px -12px rgba(0,0,0,.35);
  font-size: 13.5px; line-height: 1.45; max-width: 240px;
  opacity: 0;
  transform: translate(-50%, -118%);
  transition: opacity .15s ease;
  z-index: 3;
}
.lir-map__tip.is-on { opacity: 1; }
.lir-map__tip b { display: block; font-weight: 600; color: var(--ink); }
.lir-map__tip i { font-style: normal; color: var(--muted); font-size: 12.5px; }

/* The key is a <ul> of <li class="is-mp"><i></i>MPs</li>. It used to be one
   element per kind with a ::before, and the rules below were still written for
   that: the list got a stray dot of its own and each item's swatch was
   unstyled, which is why the key showed four dots against three labels in the
   wrong colours. One rule per kind now, matching the plugin's markup. */
.lir-map__key {
  list-style: none; margin: 12px 0 0; padding: 0;
  display: flex; gap: 18px; flex-wrap: wrap;
  font-size: 13px; color: var(--body);
}
.lir-map__key li { display: flex; gap: 7px; align-items: center; }
.lir-map__key i {
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--pin-member); border: 1.5px solid #fff;
  box-shadow: 0 0 0 1px var(--hairline);
}
.lir-map__key .is-mp i         { background: var(--pin-mp); }
.lir-map__key .is-msp i        { background: var(--pin-msp); }
.lir-map__key .is-councillor i { background: var(--pin-councillor); width: 14px; height: 14px; }
.lir-map__key .is-nomination i {
  border-radius: 3px; width: 14px; height: 12px;
  background: rgba(228, 0, 59, .28);
  border: 1px solid var(--accent);
  box-shadow: none;
}
.lir-map__credit { font-size: 11px; color: var(--muted); margin: 10px 0 0; }

/* ---- Endorser cards ----

   Compact and quiet: three across, in pages of nine that swipe sideways. The
   old card was a 72px portrait beside the words, which at three across left
   room for about a sentence and made every card shout. The quote leads now and
   the person signs it, which is the order you actually read them in. */

/* Two balanced columns. The gap is the column gap and the card's own bottom
   margin, so vertical and horizontal spacing match. */
.lir-ecards__page { column-gap: 16px; padding: 2px; }
.lir-ecard { margin-bottom: 16px; }

.lir-ecard {
  gap: 14px;
  background: var(--card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-surface);
  padding: 18px 20px;
}

/* The body face at a normal weight: this is a person talking, not a headline.
   It was locked to the display face at 700 by a rule further down the sheet,
   which is why lightening it here had no effect at all. */
.lir-ecard__words {
  margin: 0; padding: 0; border: 0;
  font-family: 'Archivo', -apple-system, BlinkMacSystemFont, sans-serif;
  font-weight: 400;
  font-size: 16px; line-height: 1.6; color: var(--body);
}

.lir-ecard__who { margin: 0; gap: 13px; }
/* Square with the card's own radius. Circles were the only round thing on the
   site and read as a different design. */
.lir-ecard__photo,
.lir-ecard__mono { width: 56px; height: 56px; border-radius: var(--r-control); flex: none; }
.lir-ecard__photo { object-fit: cover; display: block; }
.lir-ecard__mono {
  display: flex; align-items: center; justify-content: center;
  background: rgba(228, 0, 59, .08);
  color: var(--accent-dark);
  font-weight: 700; font-size: 18px; line-height: 1;
}
.lir-ecard--councillor .lir-ecard__mono { background: rgba(154, 53, 47, .13); }
.lir-ecard--msp .lir-ecard__mono { background: rgba(31, 78, 121, .12); color: var(--pin-msp); }
.lir-ecard--mp .lir-ecard__mono  { background: rgba(47, 107, 79, .12); color: var(--pin-mp); }

.lir-ecard__name { font-weight: 600; font-size: 15.5px; color: var(--ink); line-height: 1.3; }
/* Their ward, constituency or region — or, for everybody else, their town.
   Small caps kept it from competing with the name. */
/* Sentence case. Small caps shouted a ward name louder than the person's. */
.lir-ecard__place {
  color: var(--muted); font-size: 13.5px;
  font-weight: 400; line-height: 1.45;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---- paging ---- */
.lir-ecards__nav { margin-top: 18px; }
.lir-ecards__arrow {
  background: none; border: 0; cursor: pointer;
  font-size: 1.7rem; line-height: 1; padding: 0 6px;
  color: var(--accent-dark); opacity: .6;
}
.lir-ecards__arrow:hover { opacity: 1; }
.lir-ecards__arrow[disabled] { opacity: .2; cursor: default; }
.lir-ecards__dots { gap: 7px; }
.lir-ecards__dot {
  width: 8px; height: 8px; padding: 0; border: 0; border-radius: 50%;
  background: var(--accent); opacity: .22; cursor: pointer;
}
.lir-ecards__dot.is-on { opacity: 1; }

@media (max-width: 480px) {
  .lir-ecard { padding: 16px; }
  .lir-ecard__words { font-size: 15px; }
}

/* The band the strip sits in under Back Joe. Shallower than a content band —
   it is a show of hands between two things, not a section of its own — and
   with no rule above it: the row already reads as its own thing, and a line
   made it look like the start of a section that never arrived. */
.band--endorsers { padding: 0 0 30px; background: var(--paper); border-top: 0; border-bottom: 0; }
.band--endorsers .band__kicker { margin-bottom: 12px; }

/* ---- Endorser strip ----
   Faces and names under the call to action: a show of hands, read at a glance
   and never in the way of the button above it. */
/* Held to the page's own width, not the window's: a row bleeding to both edges
   of a wide screen read as a footer bar rather than part of the page. */
.lir-strip { padding: 4px 0; max-width: var(--wrap-wide); margin: 0 auto; }

/* Sits with the faces, not above them as a heading: this is a caption on a
   row of people, so it stays small and quiet and close. */
.lir-strip__label {
  font-size: 13px; font-weight: 600; color: var(--muted);
  letter-spacing: .01em; margin: 0 0 8px;
}

/* The ends fade rather than being cut. The mask is the whole effect — no
   overlay gradients that would have to be repainted for every background this
   band might sit on. */
.lir-strip__view {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 96px, #000 calc(100% - 96px), transparent 100%);
          mask-image: linear-gradient(to right, transparent 0, #000 96px, #000 calc(100% - 96px), transparent 100%);
}
.lir-strip__track { gap: 22px; padding: 2px 0; }
.lir-strip__card {
  background: var(--card);
  border: 1px solid var(--hairline);
  /* The hero photograph's corner, so the row belongs to the same page. */
  border-radius: var(--r-surface);
  padding: 12px 18px 12px 12px;
  min-width: 244px;
}
.lir-strip__photo,
.lir-strip__mono { width: 52px; height: 52px; border-radius: var(--r-control); flex: none; }
.lir-strip__photo { object-fit: cover; display: block; }
.lir-strip__mono {
  display: flex; align-items: center; justify-content: center;
  background: rgba(228, 0, 59, .08); color: var(--accent-dark);
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700; font-size: 16px; line-height: 1;
}
.lir-strip__name { font-weight: 600; font-size: 14.5px; color: var(--ink); line-height: 1.25; }
.lir-strip__place {
  color: var(--muted); font-size: 12.5px; line-height: 1.4;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Tall and thin at each end rather than a disc on top of a card: a circle
   sat over somebody's face, which is the one thing on the card worth seeing.
   Always present, because a row that moves on its own with no visible control
   looks broken rather than automatic. */
.lir-strip__arrow {
  width: 26px; height: 100%; top: 0; transform: none;
  padding: 0; cursor: pointer;
  border: 0; background: none; border-radius: 0;
  color: var(--muted-2); font-size: 26px; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  transition: color .15s ease;
}
.lir-strip__arrow:hover { color: var(--accent); }
.lir-strip__arrow:focus-visible { outline: 2px solid var(--accent-dark); outline-offset: -2px; }
@media (max-width: 600px) {
  /* A finger does the same job, and two buttons over a narrow card is clutter. */
  .lir-strip__arrow { display: none; }

  /* Portrait rather than landscape. A wide card fits one and a sliver to a
     phone screen, which reads as a broken row; a tall one fits two whole
     cards and a hint of the third, which reads as a row that continues. */
  .lir-strip__card {
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 10px;
    min-width: 0;
    width: 43vw;
    max-width: 200px;
    padding: 14px;
  }
  .lir-strip__photo,
  .lir-strip__mono { width: 100%; height: auto; aspect-ratio: 1 / 1; }
  .lir-strip__id { width: 100%; }
  .lir-strip__name { font-size: 14px; }
  /* Two lines rather than one, since there is no width to run out of. */
  .lir-strip__place { font-size: 12px; white-space: normal; }
  .lir-strip__track { gap: 12px; }

  /* The fade tightens to match: a wide one on a narrow screen eats a whole card. */
  .lir-strip__view {
    -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 34px), transparent 100%);
            mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 34px), transparent 100%);
  }
}

/* ---- map zoom buttons ---- */
.lir-map__zoom button {
  width: 30px; height: 30px; padding: 0; cursor: pointer;
  background: var(--card); color: var(--ink);
  border: 1px solid var(--hairline); border-radius: 6px;
  font-size: 15px; line-height: 1;
}
.lir-map__zoom button:hover { border-color: var(--accent); color: var(--accent-dark); }

/* Postcode check on the endorsement form */
.lir-postcode-row { display: flex; gap: 8px; align-items: stretch; }
.lir-postcode-row input { flex: 1; }
.lir-btn--quiet {
  background: transparent;
  color: var(--accent-dark);
  border: 1px solid var(--accent-dark);
  padding: 10px 18px;
}
.lir-btn--quiet:hover { background: var(--accent-dark); color: #fff; }
.lir-hint.is-found { color: var(--accent-dark); font-weight: 600; }

/* Form and map side by side.
   Produced by [labour_endorse map="right"], which renders both inside one
   wrapper — the two shortcodes on their own are separate blocks with nothing
   around them, so there would be nothing for a grid to sit on. */
.lir-endorse-with-map {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
  align-items: start;
}
@media (min-width: 860px) {
  .lir-endorse-with-map { grid-template-columns: 1.15fr .85fr; gap: 40px; }
  /* map="left" swaps the columns without changing the source order, so the
     form still comes first for a screen reader and on mobile. */
  .lir-endorse-with-map--left .lir-endorse-with-map__form { order: 2; }
  .lir-endorse-with-map--left .lir-endorse-with-map__map  { order: 1; }
}
/* In the narrower column the map wants less height than it would alone. */
.lir-endorse-with-map__map .lir-map__svg { max-height: min(70vh, 640px); }

/* Councillor nomination prompt on the endorsement form */
#lir-end-nom-wrap { margin: 16px 0 0; }
.lir-end-nom__q {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px 16px;
  margin: 0;
}
.lir-end-nom__label { font-weight: 500; color: var(--ink); }
.lir-choice { display: flex; gap: 16px; }
.lir-choice label {
  display: inline-flex; align-items: center; gap: 7px;
  margin: 0; font-weight: 400; color: var(--body); cursor: pointer;
}
.lir-choice input { width: auto; accent-color: var(--accent); }

/* Shown only when a councillor says they have not sent it yet — this is the
   one thing on the page that is an instruction rather than an invitation, so
   it is marked out rather than blending in. */
.lir-end-nom__note {
  margin: 12px 0 0;
  padding: 16px 18px;
  background: var(--paper-2);
  border-left: 3px solid var(--accent);
  border-radius: 8px;
}
.lir-end-nom__note h4 {
  margin: 0 0 6px;
  font-family: 'Playfair Display', Georgia, serif;
  font-size: 17px; font-weight: 700; color: var(--ink);
}
.lir-end-nom__note p { margin: 0 0 8px; font-size: 14.5px; line-height: 1.55; color: var(--body); }
.lir-end-nom__note p:last-child { margin-bottom: 0; }
.lir-end-nom__deadline { color: var(--accent-dark); }

/* Download link inside the nomination note — the one action in the box, so it
   reads as a button rather than another line of text.

   Selectors carry the note class as well: the form sits inside the page's
   content, where `.privacy-body a` (a class plus an element) outranks a lone
   class and was dragging the button back to underlined prose-red. */
.lir-end-nom__note a.lir-nom__form,
.lir-nom__form {
  display: inline-block;
  margin: 2px 0 4px;
  padding: 9px 16px;
  background: var(--accent);
  color: #fff;
  font-size: 14.5px;
  font-weight: 500;
  text-decoration: none;
  border-radius: 999px;
}
.lir-end-nom__note a.lir-nom__form {
  color: #fff;
  text-decoration: none;
  border-bottom: 0;
}
.lir-end-nom__note a.lir-nom__form:hover {
  background: var(--accent-dark);
  color: #fff;
  text-decoration: none;
}
.lir-nom__form:hover { background: var(--accent-dark); }
.lir-end-nom__note a:not(.lir-nom__form) {
  color: var(--accent-dark);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.lir-nom__when { color: var(--accent-dark); }

/* ============================================================
   CAMPAIGN BRAND LAYER

   Everything above is the MSP theme, unchanged. This section is
   the whole rebrand: tokens, two typefaces, the lock-up, and a
   handful of surface decisions.

   Keeping it as a layer rather than editing the rules above means
   the two themes stay diffable, and anything the plugin renders
   inherits the campaign palette through the same token bridge as
   before.

   Palette note: the brand has seven colours, but a page using all
   seven has no emphasis left. Paper carries the page, ink carries
   the type, and red marks the things you can act on. Yellow and
   plum are held for accents.

   Every value below is either one of the seven supplied colours or
   is mixed from one of them. Nothing is a new colour. The greys a
   website needs — body copy softer than full-strength ink, hairline
   borders, secondary labels — are the navy at reduced strength
   rather than separate hexes, so they stay in the family and move
   with it if the navy is ever adjusted.

   Supplied palette, and where each is used:
     #ff1f3d  red         calls to action, links, nominated seats
     #950952  plum        second accent, representative pins
     #f9e900  yellow      highlight, held back deliberately
     #101935  navy        type, the footer, and the source of every grey
     #104547  teal        the map's land, at low strength
     #191102  near-black  the imprint strip beneath the footer
     #f6f8ff  off-white   the tinted bands
   ============================================================ */

:root {
  --accent:      #ff1f3d;
  --accent-dark: #950952;
  --highlight:   #f9e900;
  --ink:         #101935;
  --teal:        #104547;
  --near-black:  #191102;

  --paper:       #ffffff;
  --paper-2:     #f6f8ff;                    /* supplied off-white */
  --card:        #ffffff;

  /* Navy at reduced strength, rather than separate greys.
     Each is declared twice: the first is a plain fallback for browsers without
     color-mix(), the second is the derived value. A browser that does not
     understand the second declaration keeps the first, so the page degrades to
     the same colours rather than to unstyled defaults. */
  --body:        #39415c;
  --muted:       #6d7594;
  --muted-2:     #8a91ad;
  --hairline:    rgba(16, 25, 53, .14);
  --body:        color-mix(in srgb, var(--ink) 82%, #ffffff);
  --muted:       color-mix(in srgb, var(--ink) 58%, #ffffff);
  --muted-2:     color-mix(in srgb, var(--ink) 46%, #ffffff);
  --hairline:    color-mix(in srgb, var(--ink) 14%, transparent);
}

/* ---- Typography ----
   Polymath for headings, Archivo for everything else. The MSP theme names
   Playfair and Poppins in a lot of individual rules, so these are set with
   !important rather than chasing every one — a deliberate trade for keeping
   the base stylesheet untouched. */
h1, h2, h3, h4,
.doc__title, .band__title, .news-card__title,
/* Polymath at 700 is the display face — right for a heading, wrong for a
   paragraph somebody has written. The quote itself is set in the body face and
   left out of this rule; the pieces below are all headings or numerals. */
.bio-body h2, .privacy-body h2,
.lir-endorsements__group,
.lir-map__stat b, .lir-ecard__mono, .lir-strip__mono {
  font-family: "polymath", 'Archivo', sans-serif !important;
  font-weight: 700 !important;
  letter-spacing: -.01em;
}
body, input, select, textarea, button,
.welcome, .band__lede, .route__desc {
  font-family: 'Archivo', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

/* ---- Masthead ----
   The MSP site swaps one logo for another on scroll: .brand--morph pins
   .brand__lock absolutely, hides it, and clamps the block to 34px high. There
   is nothing to swap to here — the campaign mark is the same at every scroll
   position — so the morph is switched off rather than re-timed. */
.topbar { height: 6px; background: var(--accent); }
/* Translucent rather than solid: the base stylesheet gives the bar a backdrop
   blur, and a solid fill would throw that away. The old rule hardcoded the MSP
   paper colour, so it has to be restated here in the campaign white. */
.site-head { background: color-mix(in srgb, var(--paper) 92%, transparent); border-bottom: 1px solid var(--hairline); }
.masthead { padding-top: 22px; padding-bottom: 22px; align-items: center; }

.brand--morph { position: static; height: auto; min-width: 0; }
.brand--morph .brand__full { display: none; }
.brand--morph .brand__lock,
.brand__lock {
  position: static;
  transform: none;
  opacity: 1;
  visibility: visible;
  transition: none;
}
/* The lock-up is drawn on .brand__name-link, not on .brand__lock. The visible
   element in the masthead is .brand__mark, which is a <div> — painting the logo
   there gives a mark that looks clickable and is not. .brand__name-link is the
   anchor that already points home, so the logo goes on that and the whole mark
   is the link. The thistle link beside it (to scottishlabour.org.uk) is hidden:
   this is a campaign site, and the mark is one thing, not two. */
.brand__thistle-link,
.brand__name,
.brand__badge { display: none; }

.brand__name-link {
  display: block;
  line-height: 0;
}
.brand__name-link::before {
  content: "";
  display: block;
  width: clamp(150px, 17vw, 210px);
  aspect-ratio: 405 / 222;
  background: url("assets/img/jfl-logo-red.png") center left / contain no-repeat;
}

/* ---- Shrink on scroll ----
   The theme's own script already toggles .is-scrolled on the masthead past
   64px; the MSP site used it to cross-fade one logo into another. There is
   nothing to cross-fade here, so the same state drives a size change instead:
   the lock-up and the padding step down together, leaving a compact bar that
   keeps the mark and the call to action in reach.

   Sticky positioning and the shadow already exist in the base stylesheet, so
   this only changes dimensions — and it transitions rather than jumping. */
.site-head { transition: box-shadow .2s ease; }
.masthead { transition: padding .22s ease; }
.brand__name-link::before { transition: width .22s ease; }

.site-head.is-scrolled .masthead {
  padding-top: 10px;
  padding-bottom: 10px;
}
.site-head.is-scrolled .brand__name-link::before {
  width: clamp(112px, 12vw, 150px);
}
.site-head.is-scrolled .navlist li:last-child a {
  padding-top: 8px;
  padding-bottom: 8px;
}

/* Someone who has asked for less movement gets the smaller bar without the
   animation, rather than no shrink at all. */
@media (prefers-reduced-motion: reduce) {
  .site-head, .masthead, .brand__name-link::before { transition: none; }
}

/* ---- Navigation ----
   Quiet links, with the last item as the one solid call to action. Whatever
   sits last in the primary menu becomes the button, so put the thing you most
   want people to do at the end. */
.navlist a {
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  transition: color .15s ease, background-color .15s ease;
}
.navlist a:hover { color: var(--accent); }
.navlist li:last-child a {
  background: var(--accent);
  color: #fff;
  padding: 10px 20px;
  border-radius: 3px;
}
.navlist li:last-child a:hover { background: var(--ink); color: #fff; }

/* ---- Hero ----
   No eyebrow and no strapline: the lock-up in the header already says who this
   is, and repeating it as type underneath competes with itself. The h1 text
   remains in the markup for search engines and screen readers. */
.hero { padding-top: clamp(28px, 4vh, 48px); align-items: center; }
.hero__name,
.eyebrow,
.strapline { display: none; }
.welcome {
  font-size: clamp(17px, 1.9vw, 21px);
  line-height: 1.65;
  color: var(--ink);
  max-width: 34ch;
  font-weight: 500;
}
.hero .hero__photo-desktop { max-width: 460px; flex: 1 1 380px; }
.hero .hero__photo-desktop img {
  aspect-ratio: 1 / 1;
  object-fit: cover;
  object-position: 50% 12%;
  border-radius: 3px;
  box-shadow: none;
}
.hero .hero__photo-mobile img {
  aspect-ratio: 4 / 3;
  object-fit: cover;
  object-position: 50% 12%;
  border-radius: 3px;
  box-shadow: none;
}

/* ---- Surfaces: flat, hairline-edged ---- */
.route, .news-card, .lir-ecard, .bio-cta, .lir-endorsement {
  background: var(--card);
  border: 1px solid var(--hairline);
  border-radius: 3px;
  box-shadow: none;
}
.bio-hero__portrait img, .bio-figure img, .news-card__img {
  border-radius: 3px;
  box-shadow: none;
}
.lir-btn, .news-more a, .lir-nom__form { border-radius: 3px; }
.lir-btn { background: var(--accent); }
.lir-btn:hover { background: var(--ink); }

/* Only the contact bar takes full-strength colour; the bands change surface
   only slightly, so the red stays the loudest thing on the page. */
.band--help    { background: var(--paper-2); }
.band--wins    { background: var(--paper); }
.band--news    { background: var(--paper-2); }
.band--signup  { background: var(--paper-2); }
.contact       { background: var(--accent); }

.route--msp::before     { background: var(--accent); }
.route--mp::before      { background: var(--ink); }
.route--council::before { background: var(--accent-dark); }

/* The footer takes the brand navy rather than the near-black. Black reads as
   an absence of colour; the navy is the campaign's own dark and sits under the
   red without arguing with it. */
.sitefoot { background: var(--ink); color: color-mix(in srgb, var(--paper-2) 68%, var(--ink)); }
.sitefoot a { color: var(--paper); }
.sitefoot__legalbar { border-top: 1px solid color-mix(in srgb, var(--paper-2) 18%, transparent); }

/* ---- Endorsement map in campaign colours ---- */
.lir-map__frame { background: var(--card); border: 1px solid var(--hairline); border-radius: 3px; }
/* The land is the teal at low strength — it recedes, and it belongs to the
   palette rather than being an invented grey-blue. */
.lir-map__area {
  fill: color-mix(in srgb, var(--teal) 12%, #ffffff);
  stroke: color-mix(in srgb, var(--teal) 28%, #ffffff);
  stroke-width: .6;
}
.lir-map__area.is-on { fill-opacity: .28; stroke: var(--accent); stroke-width: .9; }
/* The dot rules that sat here repeated the block above and, being later, quietly
   won: councillors took --accent-dark and everyone else --accent, so the
   per-kind tokens above were doing nothing. */
.lir-map__stat b { color: var(--ink); }

/* ============================================================
   Campaign hero — full-bleed red band
   Applied by adding `hero--band` to the hero group in the page.
   The MSP hero stays exactly as it was without that class, so the
   two can coexist and the change is reversible from the editor.
   ============================================================ */

.hero--band {
  width: 100%;
  max-width: none;
  padding: 0;
  display: block;
  background: var(--accent);
  color: #fff;
}
.hero--band .hero__inner {
  max-width: var(--wrap-wide);
  margin: 0 auto;
  padding: clamp(40px, 6vw, 78px) 40px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(32px, 5vw, 64px);
}
@media (max-width: 600px) {
  .hero--band .hero__inner { padding-left: 20px; padding-right: 20px; }
}
.hero--band .hero__text { flex: 1 1 420px; min-width: min(100%, 340px); }
.hero--band .hero__photo-desktop { flex: 1 1 340px; max-width: 420px; margin: 0; }
.hero--band .hero__photo-desktop img,
.hero--band .hero__photo-mobile img {
  aspect-ratio: 1 / 1;
  object-fit: cover;
  object-position: 50% 12%;
  border-radius: 3px;
  box-shadow: none;
}
@media (max-width: 760px) {
  .hero--band .hero__photo-mobile img { aspect-ratio: 4 / 3; }
}

/* The claim. Sized to be the loudest thing on the page after the lock-up. */
.hero--band .hero__head {
  font-family: "polymath", 'Archivo', sans-serif;
  font-weight: 700;
  font-size: clamp(32px, 5vw, 60px);
  line-height: 1;
  letter-spacing: -.02em;
  color: #fff;
  margin: 0 0 20px;
  max-width: 16ch;
}
.hero--band .hero__sub {
  font-size: clamp(16px, 1.8vw, 19px);
  line-height: 1.6;
  color: #fff;
  max-width: 42ch;
  margin: 0 0 16px;
  font-weight: 500;
}
.hero--band .hero__sub:last-of-type { margin-bottom: 28px; }

/* Buttons: one solid, one outlined. Both plain links in the content, so the
   office can repoint them without touching the theme. */
.hero--band .hero__cta { display: flex; gap: 12px; flex-wrap: wrap; margin: 0; }
.hero--band .hero__cta a {
  display: inline-block;
  text-decoration: none;
  font-weight: 600;
  font-size: 15px;
  padding: 13px 26px;
  border-radius: 3px;
  border: 2px solid #fff;
  transition: background-color .15s ease, color .15s ease;
}
.hero--band .hero__cta a:first-child { background: #fff; color: var(--accent); }
.hero--band .hero__cta a:first-child:hover { background: var(--ink); border-color: var(--ink); color: #fff; }
.hero--band .hero__cta a:last-child { color: #fff; }
.hero--band .hero__cta a:last-child:hover { background: #fff; color: var(--accent); }

/* ============================================================
   The arrow

   Measured off the lock-up: the "for leader" banner's point extends
   one third of the banner's height and apexes at its vertical
   centre, with a straight left edge. Everything that carries the
   arrow uses that ratio, so it reads as the same device rather than
   a generic chevron.

   --arrow-d is the depth in pixels for a given element, set to a
   third of that element's height. Extra right padding keeps the
   label clear of the point.
   ============================================================ */

/* The masthead call to action deliberately does NOT carry the arrow. The
   lock-up beside it already has one built into the "for leader" banner, and two
   points in the same bar read as a pattern rather than as a signal. The arrow
   is kept for the one action further down the page, where it is the only one. */

/* ---- "Back Joe" band ----
   Heading in a red arrow flag, mirroring the way the "for leader" banner sits
   above the name in the lock-up. Just a name and a button here: the full form
   lives on the supporters page.

   The band sits on paper rather than ink. With the hero red above it and the
   footer navy below, a dark band here would run into the footer and leave the
   page bottom-heavy; white gives the eye somewhere to rest between them.

   The flag and the button are navy, not red. The hero directly above is already
   a field of red, so a red call to action here reads as more of the same rather
   than as something to do. Navy has the contrast to carry it on white and is
   plainly a different element.

   Switch the whole thing to plum by changing --backjoe-accent below to
   var(--accent-dark); nothing else needs touching. */
/* No rule beneath: the supporter strip sits directly under this and the two
   read as one block — the ask, and the people who have already said yes. A
   line between them made the strip look like the start of something else. */
.backjoe {
  --backjoe-accent: var(--ink);
  background: var(--paper);
  color: var(--ink);
  padding: 34px 40px 20px;
}
@media (max-width: 600px) { .backjoe { padding-left: 20px; padding-right: 20px; } }

.backjoe__in {
  max-width: var(--wrap-wide);
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px 30px;
}
.backjoe__say { flex: 1 1 260px; min-width: 240px; }
.backjoe__say h2 {
  --arrow-d: 18px;
  display: inline-block;
  background: var(--backjoe-accent);
  color: #fff;
  font-family: "polymath", 'Archivo', sans-serif;
  font-weight: 700;
  font-size: clamp(20px, 2.4vw, 27px);
  line-height: 1.1;
  margin: 0 0 10px;
  padding: 8px calc(16px + var(--arrow-d)) 8px 16px;
  clip-path: polygon(
    0 0,
    calc(100% - var(--arrow-d)) 0,
    100% 50%,
    calc(100% - var(--arrow-d)) 100%,
    0 100%
  );
}
.backjoe__say p { margin: 0; font-size: 15px; line-height: 1.5; color: var(--body); }

.backjoe__form { flex: 1 1 340px; display: flex; gap: 10px; flex-wrap: wrap; align-items: stretch; }
.backjoe__form input {
  flex: 1 1 190px;
  min-width: 0;
  padding: 13px 15px;
  font: inherit;
  font-size: 16px;              /* 16px stops iOS zooming the field on focus */
  border: 1px solid var(--hairline);
  background: #fff;
  color: var(--ink);
  border-radius: 3px;
}
.backjoe__form input:focus-visible {
  outline: 2px solid var(--backjoe-accent);
  outline-offset: 1px;
  border-color: transparent;
}
.backjoe__form button,
.backjoe__form .lir-btn {
  font: inherit;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  background: var(--backjoe-accent);
  color: #fff;
  border: 0;
  padding: 13px 26px;
  border-radius: 3px;
}
/* Hover goes to the campaign red: the one place on this band where red is
   doing work, at the moment the pointer is on the thing to press. */
.backjoe__form button:hover,
.backjoe__form .lir-btn:hover { background: var(--accent); color: #fff; }
.backjoe__note { flex: 1 1 100%; margin: 0; font-size: 13px; color: var(--muted); }
.backjoe__note a { color: var(--accent-dark); }

/* clip-path is well supported, but if it is not understood the shapes simply
   stay rectangular — the padding already allows for the point, so nothing
   overlaps and nothing is lost but the silhouette. */

/* ============================================================
   Vision page — argument beside the film

   The film is a YouTube Short, so it is 9:16 rather than 16:9. A
   vertical video dropped into a full-width column looks like a
   mistake; given its own narrow column beside the text it looks
   deliberate, and it sticks while the argument scrolls past.
   ============================================================ */

/* The page template caps its children at the reading measure, which is right
   for prose but wrong for a two-column layout. The content wrapper is uncapped
   only on pages that contain a .vision grid, and its other children keep the
   measure individually. The text column still lands around 700px, so nothing
   becomes hard to read. */
.doc > .privacy-body:has(.vision),
.doc > .bio-body:has(.vision) { max-width: none; }
.privacy-body:has(.vision) > :not(.vision),
.bio-body:has(.vision) > :not(.vision) { max-width: var(--wrap-read); }

.vision {
  max-width: none;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: clamp(28px, 4vw, 56px);
  align-items: start;
}
@media (max-width: 900px) {
  /* Below this the video goes first: it is the shortest route into the
     argument, and on a phone nobody scrolls past a wall of text to find it. */
  .vision { grid-template-columns: 1fr; }
  .vision__film { order: -1; max-width: 340px; margin-inline: auto; }
}

.vision__film { position: sticky; top: 104px; }
@media (max-width: 900px) { .vision__film { position: static; } }

.vision__embed {
  position: relative;
  aspect-ratio: 9 / 16;
  border-radius: 3px;
  overflow: hidden;
  background: var(--ink);
}
.vision__embed iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.vision__caption {
  margin: 12px 0 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--muted);
}

/* The argument itself */
.vision__body > *:first-child { margin-top: 0; }
.vision__lede {
  font-family: "polymath", 'Archivo', sans-serif;
  font-weight: 700;
  font-size: clamp(21px, 2.4vw, 27px);
  line-height: 1.25;
  letter-spacing: -.01em;
  color: var(--ink);
  margin: 0 0 26px;
}
.vision__body h2 {
  font-size: clamp(20px, 2.2vw, 25px);
  line-height: 1.2;
  margin: 38px 0 12px;
  color: var(--ink);
}
.vision__body p {
  font-size: 17px;
  line-height: 1.7;
  color: var(--body);
  margin: 0 0 16px;
}
/* One pulled line per section. A red rule and a change of size, rather than a
   filled shape: the arrow is the campaign's signature and it should appear
   once on a page, not beside every emphasis. Used sparingly — a page where
   everything is emphasised has nothing emphasised. */
.vision__pull {
  display: block;
  margin: 30px 0;
  padding: 2px 0 2px 22px;
  border-left: 3px solid var(--accent);
  background: none;
  color: var(--ink);
  font-family: "polymath", 'Archivo', sans-serif;
  font-weight: 700;
  font-size: clamp(19px, 2.1vw, 24px);
  line-height: 1.3;
  letter-spacing: -.01em;
  clip-path: none;
}

/* ---- Block layout gap ----
   theme.json sets the block gap to zero, but a page saved earlier may carry
   inline spacing of its own, and core's flow layout still applies a gap to
   direct children in some contexts. The bands and the hero manage their own
   vertical rhythm with padding, so any gap between them is unwanted. */
.hero,
.hero__inner,
.backjoe,
.band,
.contact,
.entry-content > .backjoe,
.entry-content > .band {
  margin-block-start: 0;
  margin-block-end: 0;
}
/* The raw-HTML Back Joe band is a sibling of the flow layout, so it picks up
   the gap from whichever block precedes it. */
.wp-block-post-content > .backjoe { margin-top: 0; }

/* ---- Social icons ----
   Bottom right of the legal bar, opposite the imprint. The SVGs are set to
   currentColor, so they take the footer's own text colour and lift to white on
   hover — one file serves any background. */
/* The imprint sits on the near-black: a shade deeper than the footer above it,
   so the legal line reads as a footing rather than as another column. */
.sitefoot__legalbar {
  background: var(--near-black);
  margin-top: 8px;
  padding-top: 18px;
  padding-bottom: 18px;
  border-top: 0;
  display: flex;
  align-items: center;
  gap: 16px 24px;
  flex-wrap: wrap;
}
.sitefoot__copy { flex: 1 1 auto; }

.sitefoot__social {
  display: flex;
  align-items: center;
  gap: 16px;
  list-style: none;
  margin: 0;
  padding: 0;
  margin-left: auto;
}
.sitefoot__social a {
  display: block;
  color: inherit;
  border: 0;
  transition: color .15s ease, transform .15s ease;
}
.sitefoot__social svg {
  display: block;
  width: 21px;
  height: 21px;
}
.sitefoot__social a:hover,
.sitefoot__social a:focus-visible {
  color: #fff;
  transform: translateY(-1px);
}
.sitefoot__social a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
  border-radius: 2px;
}
@media (max-width: 600px) {
  .sitefoot__social { margin-left: 0; }
}

/* ---- Footer, rebuilt as blocks ----
   The footer is now real block content in parts/footer.html, editable in
   Appearance → Editor. These rules cover what the block markup adds: core's
   social-links block replaces the hand-inlined SVGs, and the legal bar is a
   flex group rather than a hand-built row.

   The old jfmsp/footer dynamic block is still registered so that any page
   holding one keeps working, but nothing in the theme uses it now. */

/* Core's social links, sized and coloured to match the footer. */
.sitefoot .wp-block-social-links {
  margin: 0;
  gap: 10px;
}
.sitefoot .wp-block-social-link {
  margin: 0;
  background: none;
}
.sitefoot .wp-block-social-links.is-style-logos-only .wp-block-social-link a {
  padding: 0;
  color: inherit;
}
.sitefoot .wp-block-social-links .wp-block-social-link-anchor svg {
  width: 21px;
  height: 21px;
  transition: transform .15s ease, opacity .15s ease;
  opacity: .82;
}
.sitefoot .wp-block-social-link a:hover svg,
.sitefoot .wp-block-social-link a:focus-visible svg {
  opacity: 1;
  transform: translateY(-1px);
}
.sitefoot .wp-block-social-link a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
  border-radius: 2px;
}

/* The legal bar is a flex group in the markup; keep the imprint left and the
   icons right, and let them stack rather than crush on a phone. */
.sitefoot__legalbar.wp-block-group {
  gap: 14px 24px;
}
.sitefoot__legalbar .sitefoot__copy { margin: 0; }

/* Block paragraphs inside the columns pick up core's margins; the footer sets
   its own rhythm. */
.sitefoot__col > p { margin: 0 0 6px; }
.sitefoot__col > p:last-child { margin-bottom: 0; }
.sitefoot__col .sitefoot__h { margin-top: 0; }

/* ---- Footer columns ----
   The name is set in the heading face, not the body face: it is the one place
   in the footer that should read as a mark rather than as information. */
.sitefoot__name {
  font-family: "polymath", 'Archivo', sans-serif;
  font-weight: 700;
  font-size: clamp(21px, 2.2vw, 26px);
  line-height: 1.05;
  letter-spacing: -.01em;
  color: #fff;
  margin: 0 0 8px;
}
.sitefoot__blurb {
  margin: 0 0 14px;
  max-width: 30ch;
  font-size: 14.5px;
  line-height: 1.55;
}
.sitefoot__privacy { margin: 0; font-size: 14px; }

/* "Get help" is the one action in the footer, and it belongs to the
   constituency side rather than the campaign — outlined rather than solid, so
   it does not compete with the campaign's own calls to action further up. */
.sitefoot__cta { margin: 0 0 12px; }
.sitefoot__cta a {
  display: inline-block;
  padding: 10px 20px;
  border: 2px solid currentColor;
  border-radius: 3px;
  font-size: 14.5px;
  font-weight: 600;
  text-decoration: none;
  color: #fff;
  transition: background-color .15s ease, color .15s ease;
}
.sitefoot__cta a:hover,
.sitefoot__cta a:focus-visible {
  background: #fff;
  color: var(--ink);
}

/* ============================================================
   Mobile: hero order, and the collapsing menu
   ============================================================ */

/* ---- Hero order on a phone ----
   The portrait belongs under the headline, not under the buttons: the claim,
   then the face, then the argument. Done with flex order rather than by moving
   the block, so the reading order in the markup stays sensible for a screen
   reader and the page can still be edited normally. */
@media (max-width: 760px) {
  .hero--band .hero__text {
    display: flex;
    flex-direction: column;
  }
  .hero--band .hero__text > .hero__head        { order: 1; }
  .hero--band .hero__text > .hero__photo-mobile { order: 2; margin: 4px 0 22px; }
  .hero--band .hero__text > .hero__sub          { order: 3; }
  .hero--band .hero__text > .hero__cta          { order: 4; margin-top: 10px; }
}

/* ---- Menu toggle ----
   Hidden on wide screens; the menu is an ordinary row there. */
.masthead__toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  cursor: pointer;
}
.masthead__toggle-bars,
.masthead__toggle-bars::before,
.masthead__toggle-bars::after {
  display: block;
  width: 24px;
  height: 2.5px;
  background: currentColor;
  border-radius: 2px;
  transition: transform .2s ease, opacity .2s ease;
}
.masthead__toggle-bars { position: relative; }
.masthead__toggle-bars::before,
.masthead__toggle-bars::after { content: ""; position: absolute; left: 0; }
.masthead__toggle-bars::before { top: -7px; }
.masthead__toggle-bars::after  { top: 7px; }

/* Bars become a cross while the menu is open. */
body.menu-open .masthead__toggle-bars { background: transparent; }
body.menu-open .masthead__toggle-bars::before { transform: translateY(7px) rotate(45deg); }
body.menu-open .masthead__toggle-bars::after  { transform: translateY(-7px) rotate(-45deg); }

@media (max-width: 780px) {
  .masthead { flex-wrap: wrap; }
  .masthead__toggle { display: flex; }

  /* The menu drops beneath the bar rather than covering the page: with three
     items an overlay is more ceremony than it needs. */
  .masthead__nav {
    flex: 1 0 100%;
    display: none;
    padding: 6px 0 4px;
  }
  body.menu-open .masthead__nav { display: block; }

  .navlist {
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
  }
  .navlist a {
    display: block;
    padding: 12px 2px;
    border-bottom: 1px solid var(--hairline);
  }
  .navlist li:last-child { margin-top: 10px; }
  /* The call to action keeps its shape rather than becoming another list row. */
  .navlist li:last-child a {
    display: inline-block;
    border-bottom: 0;
    padding: 12px 22px;
  }
}

/* ---------------------------------------------------------------------------
   News cards — a core query loop, framed
   Scoped to .news-cards deliberately: archives and any other query loop on the
   site keep the theme's ordinary post styling. Add the class to the Query Loop
   block in the editor (Advanced → Additional CSS class).
   ------------------------------------------------------------------------- */
.news-cards .wp-block-post-template { gap: 20px; margin: 0; }
.news-cards .wp-block-post-template > li {
  display: flex; flex-direction: column;
  background: var(--card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-surface);
  overflow: hidden;
}
.news-cards .wp-block-post-featured-image { margin: 0; }
.news-cards .wp-block-post-featured-image img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* No photograph: hold the same shape rather than letting one card ride up. */
.news-cards .wp-block-post-featured-image:empty { aspect-ratio: 16 / 9; background: var(--paper-2); }
.news-cards .wp-block-post-date {
  margin: 14px 16px 0; font-size: 12px; letter-spacing: .05em;
  text-transform: uppercase; color: var(--muted-2);
}
.news-cards .wp-block-post-title { margin: 6px 16px 0; font-size: 1.05rem; line-height: 1.3; }
.news-cards .wp-block-post-title a { text-decoration: none; color: var(--ink); }
.news-cards .wp-block-post-title a:hover { color: var(--accent); }
.news-cards .wp-block-post-excerpt { margin: 6px 16px 18px; }
.news-cards .wp-block-post-excerpt__excerpt { font-size: .95rem; color: var(--muted); }
.news-cards .wp-block-post-excerpt__more-text { display: none; }
@media (max-width: 782px) {
  .news-cards .wp-block-post-template { grid-template-columns: 1fr !important; gap: 16px; }
}
