/* http://meyerweb.com/eric/tools/css/reset/
   v2.0 | 20110126
   License: none (public domain)
*/

html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
}

/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
  display: block;
}

body {
  line-height: 1;
}

ol,
ul {
  list-style: none;
}

blockquote,
q {
  quotes: none;
}

blockquote:before,
blockquote:after,
q:before,
q:after {
  content: '';
  content: none;
}

table {
  border-collapse: collapse;
  border-spacing: 0;
}

/* Variables */

/* The two typefaces of the old site: Merriweather for reading, Lato for
   headings, menus and the small print around them. Served from /vendor/,
   copied out of the @fontsource packages, Latin subset only. */

@font-face {
  font-family: "Merriweather";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/vendor/fonts/merriweather-latin-300-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Merriweather";
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  src: url("/vendor/fonts/merriweather-latin-300-italic.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Merriweather";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/vendor/fonts/merriweather-latin-400-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Merriweather";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/vendor/fonts/merriweather-latin-400-italic.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Merriweather";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/vendor/fonts/merriweather-latin-700-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Lato";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/vendor/fonts/lato-latin-300-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Lato";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/vendor/fonts/lato-latin-400-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Lato";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/vendor/fonts/lato-latin-700-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Lato";
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url("/vendor/fonts/lato-latin-900-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* The fixed header's height: the header is set to it, and the title
     bands count it in to centre their text in what shows below. */
  --header-height: 4rem;
  --font-serif: "Merriweather", Georgia, serif;
  --font-sans: "Lato", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --color-primary: rgba(66, 55, 128, 1);
  --color-primary-75: rgba(66, 55, 128, 0.75);
  --color-primary-60: rgba(66, 55, 128, 0.6);
  /* The band behind page titles: the purple at about a tenth, on white. */
  --color-primary-tint: #ecebf3;
  /* The headings of the header menu, on the purple. */
  --color-primary-light: #c9c3ee;

  --color-white: #fff;
  --color-black: #000;

  /* One grey scale for the whole site, darkest first. 500 is the lightest
     that still reads as text on white (4.5:1), which is what the dates and
     other small print use; the lighter ones are for rules and fills. */
  --color-grey-900: #222;
  --color-grey-800: #333;
  --color-grey-700: #555;
  --color-grey-600: #666;
  --color-grey-500: #767676;
  --color-grey-400: #ccc;
  --color-grey-300: #ddd;
  --color-grey-200: #eee;
  --color-grey-100: #f6f6f9;

  /* One type scale, fluid between a phone (360px) and a laptop (1440px):
     each step grows with the viewport and stops at its desktop size, so a
     heading never needs a size per breakpoint. -1 and 0 stay fixed. */
  --step--1: 0.875rem;
  --step-0: 1rem;
  --step-1: clamp(1.0625rem, 1rem + 0.25vw, 1.25rem);
  --step-2: clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem);
  --step-3: clamp(1.5rem, 1.25rem + 1.1vw, 2rem);
  --step-4: clamp(1.5rem, 1.1rem + 1.8vw, 2.5rem);
  --step-5: clamp(2rem, 1.4rem + 2.8vw, 3.5rem);
  --step-6: clamp(2.25rem, 1.2rem + 4.5vw, 5rem);
}

@media (min-width: 769px) {
  :root {
    --header-height: 4.5rem;
  }
}

/* Global Styles */

/* The attribute has to win over any display a component sets, or a grid
   asked to hide stays on screen. */
[hidden] {
  display: none !important;
}

/* For labels a screen reader needs and the design already implies. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

body {
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.6;
  color: var(--color-grey-800);
  background-color: var(--color-white);
}

h1,
h2,
h3 {
  line-height: 1.3;
  color: var(--color-grey-900);
}

/* Where the old site set Lato. Everything else reads in Merriweather. */
h1,
h2,
h3,
h4,
h5,
h6,
button,
input,
select,
.header,
.footer,
.pagination,
.button,
.page-lead,
.home-search,
.article-start,
.article-date,
.article-location,
.article-category,
.timeline--date,
.press-list--date,
.article-card--date,
.article-card--location,
.latest-article--date,
.latest-article--location,
.article-tradition__intro,
.article-tradition__metadata,
.explorer-filters,
.leaflet-container {
  font-family: var(--font-sans);
}

.page-lead {
  font-weight: 300;
}

/* Headings and buttons bold; capitals only where the text works as a label. */
h1,
h2,
h3,
h4,
h5,
h6 {
  font-weight: 700;
}

/* The bar's own links, a step up from the body and with more air on a
   desktop, still below the site's name. */
@media (min-width: 769px) {
  .header .header-nav > a,
  .header-nav .header-nav--toggle {
    font-size: 1.125rem;
    margin-left: clamp(1rem, 2vw, 2rem);
  }
}

.button,
.article-start {
  font-weight: 700;
}



/* The category tiles and the headings inside the header menu stayed in
   Merriweather; the menu's slogan in its light italic. */
#home-categories .article-card--title,
.header-menu--title {
  font-family: var(--font-serif);
}

h1 {
  font-size: var(--step-4);
  margin-bottom: 1rem;
}

h2 {
  font-size: var(--step-2);
  margin: 1rem 0 0.5rem;
}

p {
  margin-bottom: 1rem;
  color: var(--color-grey-700);
}

a {
  color: var(--color-primary);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

/* One visible focus for everything that takes it, in the brand colour on
   paper and in white on the purple and over the photos. */
:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.header :focus-visible,
.footer :focus-visible,
.latest-articles :focus-visible,
.localities-section :focus-visible,
.article-gallery--intro :focus-visible {
  outline-color: var(--color-white);
}

/* Header */

/* A fixed height, not whatever the fluid name makes it, so the title bands
   below can count on it. */
.header {
  background-color: var(--color-primary);
  box-sizing: border-box;
  height: var(--header-height);
  display: flex;
  align-items: center;
  padding: 0 2rem;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1000;
  transition: opacity 0.3s ease;
}

/* On the article deck the header gets out of the way of the photos, as the
   original's did: whole over the intro, gone from the first photo on, and
   back while the pointer is over it, or focus or the open menu is inside.
   The slide script sets the class; it stays clickable while invisible so
   that pointing at it can bring it back. */
@media (min-width: 1280px) {
  body.article-page .header.header--faded {
    opacity: 0;
  }

  body.article-page .header.header--faded:hover,
  body.article-page .header.header--faded:focus-within,
  body.article-page .header.header--faded:has(.is-open) {
    opacity: 1;
  }
}

.header-container {
  flex: 1;
  max-width: 1920px;
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.header-nav {
  display: flex;
  align-items: center;
}

.header-nav a,
.header-nav--toggle {
  color: var(--color-white);
  margin-left: 1rem;
}

/* The dropdown of the original header: categories and the ways into the
   archive, in a panel the full width of the page under the bar. */

.header-nav--toggle {
  font: inherit;
  line-height: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

.header-nav--toggle::after {
  content: '';
  display: inline-block;
  width: 0.4em;
  height: 0.4em;
  margin-left: 0.45em;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-0.2em) rotate(45deg);
  transition: transform 0.2s ease;
}

.header-nav--item__expands.is-open .header-nav--toggle::after {
  transform: translateY(0.05em) rotate(-135deg);
}

.header-nav--toggle:focus-visible,
.header-menu a:focus-visible {
  outline: 2px solid var(--color-white);
  outline-offset: 2px;
}

.header-menu {
  display: none;
}

.header-nav--item__expands.is-open .header-menu {
  display: block;
}

.header-menu ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.header-menu a {
  margin: 0;
}

.header-menu--title {
  margin: 0 0 0.75rem;
  font-size: 1.1rem;
  font-weight: 300;
  color: var(--color-primary-light);
}

@media (min-width: 769px) {
  /* Stretched over the height of the bar, and a little past its bottom edge
     into the panel, so the pointer does not drop out of the item, and the
     panel with it, on its way down. Ending flush left a few pixels' gap. */
  .header-nav .header-nav--toggle {
    padding: 1.25rem 0 2rem;
    margin-top: -1.25rem;
    margin-bottom: -2rem;
  }

  .header-nav--item__expands:hover .header-menu {
    display: block;
  }

  .header-menu {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background-color: var(--color-primary);
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
  }

  .header-menu--wrapper {
    display: grid;
    grid-template-columns: 1fr 2fr 1fr;
    gap: 2rem;
    max-width: 1920px;
    margin: 0 auto;
    padding: 2.5rem 2rem 3rem;
  }

  .header-menu--slogan {
    margin: 0;
    font-family: var(--font-serif);
    font-style: italic;
    font-weight: 300;
    color: var(--color-white);
    font-size: var(--step-2);
    line-height: 1.4;
  }

  .header-menu--column {
    border-left: 1px solid rgba(255, 255, 255, 0.25);
    padding-left: 2rem;
  }

  .header-menu--column__categories ul {
    columns: 2;
    column-gap: 2rem;
  }

  .header-menu li {
    break-inside: avoid;
    margin-bottom: 0.4rem;
    line-height: 1.4;
  }
}

.header-hamburger {
  display: none;
  flex-direction: column;
  justify-content: space-around;
  width: 2rem;
  height: 2rem;
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 0;
  z-index: 10;
}

.header-hamburger span {
  width: 2rem;
  height: 0.25rem;
  background: var(--color-white);
  border-radius: 10px;
  transition: all 0.3s linear;
  position: relative;
  transform-origin: 1px;
}

.header-hamburger.is-active span:first-child {
  transform: rotate(45deg);
}

.header-hamburger.is-active span:nth-child(2) {
  opacity: 0;
  transform: translateX(20px);
}

.header-hamburger.is-active span:nth-child(3) {
  transform: rotate(-45deg);
}

@media (max-width: 768px) {
  .header-hamburger {
    display: flex;
  }

  .header-nav {
    display: none;
    flex-direction: column;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background-color: var(--color-primary);
    padding: 1rem 2rem;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  }

  .header-nav.is-open {
    display: flex;
  }

  .header-nav {
    align-items: stretch;
    /* The accordion can outgrow a short screen. */
    max-height: calc(100vh - 4rem);
    overflow-y: auto;
  }

  .header-nav a,
  .header-nav .header-nav--toggle {
    margin: 0.5rem 0;
    font-size: 1.2rem;
    text-align: left;
  }

  .header-menu--slogan {
    display: none;
  }

  .header-menu {
    padding: 0 0 0.5rem 1rem;
    border-left: 2px solid rgba(255, 255, 255, 0.3);
  }

  .header-menu--column {
    margin-top: 0.75rem;
  }

  .header-menu--title {
    margin-bottom: 0.25rem;
    font-size: 0.875rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
  }

  .header-menu a {
    display: block;
    margin: 0;
    padding: 0.3rem 0;
    font-size: 1rem;
  }
}

/* As the original set the name: Lato Black in capitals, slightly spaced,
   from 1rem on a phone to 1.3rem on a desktop. */
.header-logo--title {
  font-size: clamp(1rem, 0.9rem + 0.444vw, 1.3rem);
  font-weight: 900;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--color-white);
  margin: 0
}

.header-logo--title a,
.header-logo--title a:visited {
  color: var(--color-white);
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
}

.header-logo--mark {
  /* The original sat the pin at 20px next to the name, 35px from desktop up. */
  width: 1.25rem;
  height: auto;
  flex: none;
}

@media (min-width: 768px) {
  .header-logo--mark {
    width: 1.6rem;
  }
}

/* Main Container */

.main-container {
  --container-padding: 2rem;
  margin: 0 auto;
  max-width: 1920px;
  padding: var(--container-padding);
  padding-top: 6rem;
}

/* Home Page */

body.home-page {
  .main-container {
    max-width: none;
    padding: 0;
    /* The carousel starts below the fixed header, not behind it, which hid
       the top of every photo and set the arrows off its visible centre. */
    padding-top: var(--header-height);
  }
}

.categories-section {
  margin: 0 auto 2rem;
  max-width: 1920px;
  padding: 0 2rem 2rem;
  text-align: center;
}

.categories-section--head {
  margin-bottom: 1rem;
  padding-top: 3rem;
}

@media (min-width: 768px) {
  .categories-section {
    margin: 0 auto 4rem;
  }
}

.categories-section-title {
  color: var(--color-primary);
  font-size: var(--step-4);
  font-weight: bold;
  margin-bottom: 2rem;
}

/* The search on the home page, under the categories heading. Its results
   replace the tiles, as ordinary article cards. */

.home-search {
  max-width: 36rem;
  margin: 0 auto 1rem;
}

.home-search--input {
  width: 100%;
  box-sizing: border-box;
  padding: 0.85rem 1rem 0.85rem 3rem;
  font: inherit;
  /* 16px on a phone, the least iOS takes without zooming into the field. */
  font-size: clamp(1rem, 0.9rem + 0.4vw, 1.1rem);
  color: var(--color-grey-800);
  border: 2px solid var(--color-primary-60);
  border-radius: 2rem;
  background: var(--color-white) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23423780' stroke-width='2.5' stroke-linecap='round'%3E%3Ccircle cx='10.5' cy='10.5' r='6.5'/%3E%3Cpath d='M15.5 15.5 21 21'/%3E%3C/svg%3E") no-repeat 1.1rem center / 1.25rem;
}

.home-search--input:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--color-primary-60);
}

.home-search--status {
  min-height: 1.6em;
  margin: 0;
  color: var(--color-grey-600);
}

.home-search--results {
  text-align: left;
}

/* Pages */

/* Titles sit on a light purple band the width of the window. It runs up
   behind the fixed header so it starts right at its edge, and its padding
   counts the header's height in, so the text has as much room above as
   below; the shadow carries it past the content's column. */
.page-header {
  margin: calc(-1 * 6rem) 0 2rem;
  padding: calc(var(--header-height) + 1.5rem) 0 1.5rem;
  background-color: var(--color-primary-tint);
  box-shadow: 0 0 0 100vmax var(--color-primary-tint);
  clip-path: inset(0 -100vmax);
}

.page-title {
  font-size: var(--step-4);
  font-weight: bold;
  color: var(--color-primary);
}

.page-header > :last-child {
  margin-bottom: 0;
}

/* What the title belongs to: the region of a municipality. */
.page-title--context {
  margin: -0.5rem 0 0;
  font-size: var(--step-1);
}

/* Article Page */

/* The call to action only makes sense where the deck is: on narrower screens
   the photos already follow the text in reading order. Scoped to the page so
   it outranks the shared .button rule, whatever the order of the file. */
body.article-page .article-start {
  display: none;
}

/* Below the slide-deck breakpoint the article is an ordinary stacked page:
   a readable column for the text and the gallery photos one after another,
   with room to breathe. Everything here is overridden from 1280px up. */

body.article-page .main-container {
  max-width: 60rem;
}

.slides--slide + .slides--slide {
  margin-top: 1.5rem;
}

/* Below the deck the photos and videos follow one another down the page;
   a short rule between each two keeps them from running together. */
@media (max-width: 1279px) {
  .slides--slide:has(> .article-gallery--media) + .slides--slide:has(> .article-gallery--media)::before {
    content: '';
    display: block;
    width: 3rem;
    height: 2px;
    margin: 0.5rem auto 2rem;
    background-color: var(--color-primary-60);
  }
}

.article-gallery--media .article-gallery--photo {
  border-radius: 4px;
  /* Stacked reading order below the deck: the photo keeps the shape the
     old background-image gave it. */
  aspect-ratio: 3 / 2;
  display: block;
  width: 100%;
  height: auto;
  object-fit: cover;
  object-position: center;
}

.article-gallery--video {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
  border-radius: 4px;
  background-color: var(--color-black);
}

@media (min-width: 1280px) {
  body.article-page {
    background-color: var(--color-black);
    overflow: hidden;
  }

  body.article-page .main-container {
    --container-padding: 0px;
    padding: 0;
    max-width: none;
  }
}

@media (min-width: 1280px) {
  .article {
    position: relative;
  }
}

.article-header {
  border-bottom: 1px solid var(--color-grey-200);
  margin-bottom: 2rem;
  padding-bottom: 0.5rem;
  width: 100%;
}

/* Below the deck, where the title is not over the photo, it gets the same
   band as every other page's title. */
@media (max-width: 1279px) {
  .article-header {
    margin-top: calc(-1 * 6rem);
    padding: calc(var(--header-height) + 1.5rem) 0 1.5rem;
    border-bottom: 0;
    background-color: var(--color-primary-tint);
    box-shadow: 0 0 0 100vmax var(--color-primary-tint);
    clip-path: inset(0 -100vmax);
  }
}

.article-title {
  font-size: var(--step-5);
  font-weight: bold;
  color: var(--color-primary);
  margin-bottom: 0;
  text-transform: uppercase;
}

@media (min-width: 1280px) {
  .article-title {
    color: var(--color-grey-300);
  }
}

.article-date {
  display: inline-block;
  font-size: 0.95rem;
  color: var(--color-grey-500);
  font-style: italic;
}

.article-location {
  color: var(--color-grey-500);
  display: inline-block;
  font-size: 0.95rem;
}

.article-location:before {
  content: " · ";
  margin: 0 0.25rem;
}

/* On a phone the place rarely fits beside the date, and when it wrapped the
   separator led the new line. Stacked, it needs none. */
@media (max-width: 639px) {
  .article-date,
  .article-location {
    display: block;
  }

  .article-location:before {
    content: none;
  }
}

.article-body {
  margin-bottom: 4rem;
  font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
}

@media (min-width: 1280px) {
  .article-body {
    color: var(--color-grey-300);
    margin-bottom: 0;
  }
}

.article-body {
  width: 100%;
}

.article-body li {
  margin-bottom: 1.5rem;
}

@media (min-width: 1280px) {
  .slides--container {
    display: grid;
    grid-template-columns: 1fr;
    height: 100vh;
    overflow-y: scroll;
    scroll-snap-type: y mandatory;
    scrollbar-width: none;
    -ms-overflow-style: none;
  }

  .slides--container::-webkit-scrollbar {
    display: none;
  }

  .slides--slide,
  .slides--slide + .slides--slide {
    grid-column: 1;
    height: 100vh;
    scroll-snap-align: start;
    /* Stop at every photo: a hard flick should not fly past several. */
    scroll-snap-stop: always;
    width: 100%;
    margin-top: 0;
  }

  .article-gallery--media .article-gallery--photo {
    border-radius: 0;
  }

  /* The intro is a slide of its own, over the article's featured photo, so
     every slide is a real scroll-snap stop and the browser can do the
     scrolling itself. */
  .article-gallery {
    height: 100%;
    width: 100%;
    /* The scrim rides on the photo so both reach the edges. Putting it on
       the intro instead left the sides unshaded on screens wider than the
       1920px the intro is capped at. */
    background-image: linear-gradient(rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0.75)),
      var(--intro-desktop-hd);
    background-size: cover;
    background-position: center center;
  }

  .article-gallery--intro {
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    padding: 0 15rem;
    box-sizing: border-box;
    max-width: 1920px;
    margin: 0 auto;
    transition: opacity 0.3s ease;
  }

  body.article-page .article-start {
    display: inline-block;
    margin-top: 1.5rem;
    align-self: flex-start;
    border: 0;
    font: inherit;
    font-family: var(--font-sans);
    font-weight: 700;
    cursor: pointer;
  }

  .article-gallery--intro a {
    color: var(--color-white);
    text-decoration: underline;
    text-decoration-color: rgba(255, 255, 255, 0.5);
    text-underline-offset: 2px;
  }

  .article-gallery--intro a:hover {
    text-decoration-color: var(--color-white);
  }

  .article-gallery--media {
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .article-gallery--media .article-gallery--photo {
    /* On the deck the slide is the viewport: the photo is as tall as it is
       allowed and shown whole, letterboxed, rather than cropped. */
    height: 90vh;
    width: 100%;
    max-width: 1920px;
    aspect-ratio: auto;
    object-fit: contain;
  }

  /* As large as the slide allows while staying 16:9. */
  .article-gallery--media .article-gallery--video {
    width: min(100%, 1920px, 90vh * 16 / 9);
    border-radius: 0;
  }

  .article-header {
    border-bottom: none;
    margin-bottom: 2rem;
    color: var(--color-white);
  }

  .article-title {
    color: var(--color-white) !important;
    font-size: 4rem;
    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
  }

  .article-body {
    color: var(--color-white) !important;
    text-shadow: 0 1px 5px rgba(0, 0, 0, 0.5);
  }

  /* Slide navigation dots */
  .slides-nav {
    position: fixed;
    right: 2rem;
    top: 50%;
    transform: translateY(-50%);
    z-index: 100;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    opacity: 0;
    transition: opacity 0.3s ease;
    pointer-events: none;
  }

  .slides-nav.visible {
    opacity: 1;
    pointer-events: auto;
  }

  .slides-nav-dot {
    width: 10px;
    height: 10px;
    padding: 0;
    border-radius: 50%;
    background-color: rgba(255, 255, 255, 0.4);
    cursor: pointer;
    transition: all 0.3s ease;
    border: 2px solid transparent;
    appearance: none;
  }

  .slides-nav-dot:focus-visible {
    outline: 2px solid var(--color-white);
    outline-offset: 3px;
  }

  .slides-nav-dot:hover {
    background-color: rgba(255, 255, 255, 0.7);
    transform: scale(1.2);
  }

  .slides-nav-dot.active {
    background-color: var(--color-white);
    border-color: rgba(255, 255, 255, 0.5);
    transform: scale(1.3);
  }
}

/* Responsive Images */

.responsive-image {
  background-size: cover;
  background-position: center center;
  background-repeat: no-repeat;
  padding-top: 66.5625%;
  background-image: var(--img-mobile);
}

@media (min-width: 480px) {
  .responsive-image {
    background-image: var(--img-tablet);
  }
}

@media (min-width: 640px) {
  .responsive-image {
    background-image: var(--img-desktop);
  }
}

@media (min-width: 1120px) {
  .responsive-image {
    background-image: var(--img-desktop-hd);
  }
}

/* Article Grid */

.article-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2rem;
}

@media (min-width: 480px) {
  .article-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 640px) {
  .article-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 1120px) {
  .article-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

.article-card {
  display: flex;
  flex-direction: column;
}

.article-card--link {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
  height: 100%;
}

.article-card--link:hover {
  text-decoration: none;
}

.article-card--title,
.article-card--link:hover {
  color: var(--color-primary);
}

.article-card--image {
  aspect-ratio: 4 / 3;
  display: block;
  width: 100%;
  /* Or the height attribute pins the card to the photo's own height. */
  height: auto;
  object-fit: cover;
  object-position: center;
}

.article-card--content {
  padding: 1rem 0;
}

.article-card--title {
  font-size: 1.1rem;
  font-weight: bold;
  margin: 0 0 0.5rem 0;
  line-height: 1.3;
}

.article-card--location {
  display: block;
  font-size: 0.85rem;
  color: var(--color-grey-500);
}

.article-card--date {
  display: block;
  font-size: 0.85rem;
  color: var(--color-grey-500);
}

/* Pagination */

.pagination {
  margin: 3rem 0 0;
  padding: 2rem 0 0;
  border-top: 1px solid var(--color-grey-200);
}

.pagination-links {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 2rem;
}

.pagination-link {
  display: inline-block;
  padding: 0.75rem 1.5rem;
  background-color: var(--color-primary);
  color: var(--color-white);
  border-radius: 4px;
  text-decoration: none;
  transition: background-color 0.2s ease;
}

.pagination-link:hover {
  background-color: color-mix(in srgb, var(--color-primary) 80%, transparent);
  text-decoration: none;
}

.pagination-info {
  color: var(--color-grey-600);
  font-size: 0.9rem;
}

/* Latest Articles (home carousel) */

.latest-articles {
  position: relative;
  /* The band runs edge to edge; the photo inside it does not. */
  overflow: hidden;
}

.latest-article {
  display: block;
  position: relative;
  color: inherit;
  text-decoration: none;
}

.latest-article:hover {
  text-decoration: none;
}

.latest-article--image {
  /* The ratio overrides the photo's own: on a phone the 2.5:1 crop of the
     source is too thin to carry a caption, so the box is taller and
     `object-fit` crops the photo sideways instead. */
  aspect-ratio: 3 / 2;
  display: block;
  width: 100%;
  /* No photo in the archive is wider than 1920px — the originals included —
     so past that the carousel would be stretching one: 1,33x on a 2560px
     screen, which is what makes it look soft. The original capped its whole
     body at this width (descubrejaen, basics/wrappers.scss). Here only the
     photo stops, and the backdrop fills what is left. */
  max-width: 1920px;
  margin: 0 auto;
  position: relative;
  z-index: 1;
  /* The width and height attributes would otherwise pin the height to the
     photo's own 768px and leave the ratio above with nothing to do. */
  height: auto;
  object-fit: cover;
  object-position: center;
}

/* A slide still waiting for its photo holds no space: without JavaScript the
   <noscript> copy is the one that shows, and two boxes would stack. */
.latest-article--image[data-src] {
  display: none;
}

/* Past 1920px the photo leaves a strip either side. Rather than a flat
   colour, it is the same photo blown up and blurred, which is the same file
   the browser has already fetched — no extra bytes. Scaled up a touch so the
   blur has something to bleed from and no soft edge shows. */
.latest-article--backdrop {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: blur(2rem) brightness(0.8);
  transform: scale(1.15);
  z-index: 0;
}

.latest-article--backdrop[data-src] {
  display: none;
}

.latest-article--caption {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  /* Lines up with the photo, not with the blurred strip beside it. The
     padding has to count towards the cap, or the text starts 4rem to the
     left of the photo's edge. */
  box-sizing: border-box;
  max-width: 1920px;
  margin: 0 auto;
  /* Over the arrows' edge shading, which would otherwise grey the text. */
  z-index: 3;
  padding: 2.5rem 1.25rem 1.25rem;
  color: var(--color-white);
  background: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent);
}

.latest-article--title {
  color: var(--color-white);
  font-size: clamp(1.125rem, 0.5rem + 2.6vw, 3rem);
  font-weight: bold;
  text-transform: uppercase;
  margin: 0 0 0.25rem 0;
}

/* The places and the date share a line, in normal case. */
.latest-article--location,
.latest-article--date {
  display: inline;
  font-size: clamp(0.875rem, 0.65rem + 0.9vw, 1.5rem);
  opacity: 0.85;
}

.latest-article--location::after {
  content: " · ";
}

/* Arrows only steer the carousel, so they stay hidden until it exists. */
.latest-articles--arrows {
  display: none;
}

.latest-articles.is-carousel .latest-articles--arrows {
  display: block;
  /* Same, so they sit on the photo's edges and not the viewport's. */
  max-width: 1920px;
  margin: 0 auto;
  left: 0;
  right: 0;
  position: absolute;
  top: 0;
  bottom: 0;
  pointer-events: none;
  /* Over the caption, so a title that wraps never takes the arrows' clicks. */
  z-index: 4;
}

/* A faint shade at either edge of the photo, so the white arrows hold up on
   a bright sky or a white wall. Under the caption, so it does not grey the
   text; the arrows sit above both. */
.latest-articles.is-carousel .latest-articles--track::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  max-width: 1920px;
  margin: 0 auto;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(to right, rgba(0, 0, 0, 0.35), transparent 18%, transparent 82%, rgba(0, 0, 0, 0.35));
}

.latest-articles.is-carousel .latest-articles--arrow {
  pointer-events: auto;
}

.latest-articles.is-carousel .latest-articles--track {
  position: relative;
  aspect-ratio: 3 / 2;
  /* Stated, so that the max-height further down trims the band's height
     without the ratio pulling its width in with it — the blurred strip
     needs the full width. */
  width: 100%;
}

.latest-articles.is-carousel .latest-article {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.5s linear;
}

.latest-articles.is-carousel .latest-article.is-current {
  opacity: 1;
  visibility: visible;
}

.latest-articles--arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 3rem;
  height: 3rem;
  border: 0;
  background: none;
  cursor: pointer;
  z-index: 2;
  display: grid;
  place-items: center;
}

/* The chevron grows a little under the pointer, to show where the click
   lands. The chevron, not the button: scaling the button would scale the
   offset that centres it too. */
.latest-articles--arrow::before {
  transition: scale 0.2s ease;
}

.latest-articles--arrow:hover::before,
.latest-articles--arrow:focus-visible::before {
  scale: 1.3;
}

/* A chevron drawn from two borders of a rotated square: its ink sits on the
   pointing side, so it is moved a quarter back to look centred. */
.latest-articles--arrow::before {
  content: "";
  display: block;
  width: 1.25rem;
  height: 1.25rem;
  border-top: 3px solid var(--color-white);
  border-right: 3px solid var(--color-white);
}

.latest-articles--arrow__prev {
  left: 0.5rem;
}

.latest-articles--arrow__prev::before {
  transform: translateX(25%) rotate(-135deg);
}

.latest-articles--arrow__next {
  right: 0.5rem;
}

.latest-articles--arrow__next::before {
  transform: translateX(-25%) rotate(45deg);
}

.latest-articles--arrow:focus-visible {
  outline: 2px solid var(--color-white);
}

@media (min-width: 768px) {
  .latest-article--image,
  .latest-articles.is-carousel .latest-articles--track {
    /* Wide enough now for the source crop, 2.5:1, to be shown whole. */
    aspect-ratio: 2.5 / 1;
    /* What that ratio gives a photo at its 1920px cap. Past that width the
       ratio alone would keep making the band taller than the photo in it,
       leaving the caption adrift over the blurred strip. */
    max-height: 768px;
  }

  /* As far from the arrows as the arrows are from the photo's edge: 1.5rem
     out, 4rem of arrow, 1.5rem in. */
  .latest-article--caption {
    padding: 6rem 7rem 3rem;
  }

  .latest-articles--arrow {
    width: 4rem;
    height: 4rem;
  }

  .latest-articles--arrow__prev {
    left: 1.5rem;
  }

  .latest-articles--arrow__next {
    right: 1.5rem;
  }
}

/* On a phone the photo is too small to carry the caption over it: the title,
   places and date move to a band under it, the light purple of the page
   titles, and the arrows keep to the photo, centred on it. */
@media (max-width: 639px) {
  .latest-article--caption {
    position: static;
    width: 100%;
    margin: 0;
    padding: 1rem 1.25rem 1.25rem;
    background: var(--color-primary-tint);
    color: var(--color-grey-700);
  }

  .latest-article--title {
    color: var(--color-primary);
    margin-bottom: 0.375rem;
  }

  .latest-article--location,
  .latest-article--date {
    opacity: 1;
  }

  /* Nothing past the photo's edge to fill on a phone. */
  .latest-article--backdrop {
    display: none;
  }

  .latest-articles.is-carousel .latest-articles--arrows,
  .latest-articles.is-carousel .latest-articles--track::after {
    bottom: auto;
    height: calc(100vw * 2 / 3);
  }

  /* The slides stack in one grid cell instead of over a 3:2 box, so the
     track grows to the tallest photo and caption, and every caption band
     stretches to the same height whatever its title's length. */
  .latest-articles.is-carousel .latest-articles--track {
    display: grid;
    aspect-ratio: auto;
  }

  .latest-articles.is-carousel .latest-article {
    position: relative;
    inset: auto;
    grid-area: 1 / 1;
    display: flex;
    flex-direction: column;
  }

  .latest-articles.is-carousel .latest-article--caption {
    flex: 1;
  }
}

/* Books block (home) */

.home-books {
  margin: 4rem auto;
  padding: 2rem;
  text-align: center;
}

.home-books--container {
  margin: 0 auto;
  max-width: 900px;
}

.home-books--title {
  color: var(--color-primary);
  font-size: var(--step-4);
  font-weight: bold;
  margin-bottom: 1rem;
}

.home-books--lead {
  margin: 0 auto 2rem;
  max-width: 44rem;
  color: var(--color-grey-600);
}

.home-books--list {
  display: grid;
  gap: 2.5rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

.home-books--item a {
  display: block;
  text-decoration: none;
  color: inherit;
}

.home-books--cover {
  display: block;
  width: 100%;
  height: auto;
}

.home-books--caption {
  display: block;
  margin-top: 0.75rem;
  font-weight: bold;
  color: var(--color-primary);
}

/* Books index page */

.books-index {
  display: grid;
  gap: 3rem;
  list-style: none;
  margin: 3rem 0;
  padding: 0;
}

.books-index--item a {
  display: block;
  text-decoration: none;
  color: inherit;
}

.books-index--banner {
  display: block;
  width: 100%;
  height: auto;
}

.books-index--title {
  color: var(--color-primary);
  font-size: var(--step-2);
  margin: 1rem 0 0.5rem;
}

.books-index--summary {
  margin: 0;
  color: var(--color-grey-600);
}

/* Localities Section */

.localities-section {
  background-color: var(--color-primary-60);
  /* The wide side padding only from the desktop up: on a phone it left the
     list a column 130px wide. */
  padding: 3rem 2rem;
  position: relative;
  margin-bottom: 2rem;
}

@media (min-width: 1280px) {
  .localities-section {
    padding: 3rem 8rem;
  }
}

.localities-container {
  margin: 0 auto;
  max-width: 1920px;
  position: relative;
  z-index: 2;
}

.localities-title {
  color: var(--color-white);
  font-size: var(--step-4);
  font-weight: bold;
  margin-bottom: 2rem;
  text-align: center;
}

/* Two columns even on a phone: one ran 97 names, some 3,000px, down the
   screen. A long name wraps within its column. */
.localities-list {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.6rem 1rem;
  margin-bottom: 0;
  text-align: left;
}

@media (min-width: 768px) {
  .localities-list {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 1280px) {
  .localities-list {
    grid-template-columns: repeat(4, 1fr);
  }
}

.locality-item {
  line-height: 1.25;
}

@media (max-width: 479px) {
  .localities-list .locality-link {
    font-size: 0.875rem;
  }
}

.locality-link {
  color: var(--color-white);
  font-size: 0.95rem;
  text-decoration: none;
  transition: color 0.2s ease;
}

.locality-link:hover {
  color: var(--color-primary);
  text-decoration: none;
}

.localities-map-container {
  bottom: 0;
  left: 0;
  position: absolute;
  right: 0;
  top: 0;
  z-index: -1;
}

.localities-map {
  height: 100%;
}

#localities-map .leaflet-control-container {
  display: none;
}

/* Static Pages */

.static-page .main-container {
  max-width: 52rem;
}

/* The title shares the measure of the text below it: one column, one edge. */
.page-prose,
.page-section {
  margin: 0 0 3rem;
}

/* The page's last block leaves the space above the footer to the page's
   own padding and the footer's margin. */
.page-prose:last-child,
.page-section:last-child,
.books-index:last-child,
.page-prose > :last-child {
  margin-bottom: 0;
}

.locality-wrapper:last-of-type {
  padding-bottom: 2rem;
}

.page-prose a,
.page-section a,
.home-books--lead a {
  color: var(--color-primary);
  text-decoration: underline;
  text-decoration-color: var(--color-primary-60);
  text-underline-offset: 2px;
}

.page-prose a:hover,
.page-section a:hover,
.home-books--lead a:hover {
  text-decoration-color: var(--color-primary);
}

.page-lead {
  font-size: var(--step-1);
  line-height: 1.5;
  color: var(--color-grey-800);
}

.page-section--title {
  font-size: var(--step-3);
  margin: 3rem 0 1.5rem;
  padding-bottom: 0.5rem;
  border-bottom: 2px solid var(--color-primary);
}

.page-subsection--title {
  font-size: var(--step-1);
  margin: 2.5rem 0 1rem;
  color: var(--color-primary);
}

.page-list {
  list-style: disc;
  padding-left: 1.25rem;
  margin-bottom: 1rem;
}

.page-list li {
  margin-bottom: 0.5rem;
  color: var(--color-grey-700);
}

.page-banner,
.timeline--image {
  display: block;
  width: 100%;
  height: auto;
  max-height: 24rem;
  object-fit: cover;
  border-radius: 4px;
  margin: 1rem 0 1.5rem;
}

/* Timeline */

.timeline {
  border-left: 2px solid var(--color-grey-200);
  padding-left: 1.5rem;
}

.timeline--item {
  position: relative;
  margin-bottom: 2.5rem;
}

.timeline--item::before {
  content: "";
  position: absolute;
  left: calc(-1.5rem - 6px);
  top: 0.5rem;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background-color: var(--color-primary);
}

.timeline--item__last::before {
  width: 14px;
  height: 14px;
  left: calc(-1.5rem - 8px);
  background-color: var(--color-white);
  border: 3px solid var(--color-primary);
}

.timeline--date {
  font-size: var(--step--1);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-primary-75);
  margin-bottom: 0.25rem;
}

.timeline--title {
  font-size: var(--step-2);
  font-weight: 700;
  margin-bottom: 0.5rem;
}

/* Team */

.team {
  display: grid;
  gap: 2rem;
  grid-template-columns: 1fr;
}

.team--photo {
  width: 96px;
  height: 96px;
  object-fit: cover;
  border-radius: 50%;
  margin-bottom: 0.75rem;
}

.team--name {
  font-size: 1.125rem;
  margin-bottom: 0.125rem;
}

.team--role {
  font-size: 0.875rem;
  color: var(--color-primary-75);
  margin-bottom: 0.5rem;
}

/* Press list */

.press-list li {
  padding: 0.625rem 0;
  border-bottom: 1px solid var(--color-grey-200);
  color: var(--color-grey-700);
}

.press-list--archived {
  font-size: 0.8125rem;
  color: var(--color-grey-500);
  white-space: nowrap;
}

.press-list--date {
  display: inline-block;
  min-width: 6.5rem;
  font-variant-numeric: tabular-nums;
  color: var(--color-grey-500);
  font-size: 0.875rem;
}

/* Backers */

.backers--logos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 1.5rem;
  align-items: center;
  margin-bottom: 1rem;
}

.backers--logo img {
  width: 100%;
  height: auto;
  filter: grayscale(100%);
  opacity: 0.8;
  transition: filter 0.2s ease, opacity 0.2s ease;
}

.backers--logo a:hover img {
  filter: none;
  opacity: 1;
}

.backers--names {
  /* Sized by column width, not by count: 219 names in narrow columns wrap
     constantly, and a wrapped line is what gets mistaken for a new backer. */
  columns: 16rem;
  column-gap: 2rem;
  font-size: 0.8125rem;
  line-height: 1.35;
  color: var(--color-grey-500);
}

.backers--names li {
  break-inside: avoid;
  /* A name that still wraps needs to read as one entry: the marker sits in
     the margin and the second line lines up under the first, so only a
     bullet starts a backer. */
  list-style: disc outside;
  margin: 0 0 0.5rem 1rem;
  padding-left: 0.25rem;
  hyphens: none;
}

.backers--names li::marker {
  color: var(--color-grey-400);
  font-size: 0.7em;
}

/* Footer */

.footer {
  background-color: var(--color-primary);
  color: var(--color-white);
  padding: 3rem 2rem 2rem;
  margin-top: 2rem;
}

.footer-container {
  max-width: 1920px;
  margin: 0 auto;
}

.footer a {
  color: rgba(255, 255, 255, 0.85);
}

.footer a:hover {
  color: var(--color-white);
}

.footer-sitemap {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2rem;
  padding-bottom: 2rem;
}

.footer-sitemap--title {
  font-size: 1rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: rgba(255, 255, 255, 0.75);
  margin: 0 0 0.75rem;
}

.footer-sitemap--list li {
  padding: 0.1875rem 0;
  font-size: 0.9375rem;
}

.footer-colophon {
  border-top: 1px solid rgba(255, 255, 255, 0.2);
  padding-top: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.footer-languages {
  display: flex;
  gap: 1rem;
  font-size: 0.9375rem;
}

.footer-languages--item__current span {
  color: rgba(255, 255, 255, 0.65);
}

.footer-social {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem;
}

.footer-social svg {
  width: 20px;
  height: 20px;
  fill: rgba(255, 255, 255, 0.85);
  display: block;
}

.footer-social a:hover svg {
  fill: var(--color-white);
}

.footer-social--name {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.footer-social--email {
  font-size: 0.9375rem;
}

.footer-credits {
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, 0.78);
}

.footer-credits--byline {
  color: rgba(255, 255, 255, 0.78);
  margin-bottom: 0.5rem;
}

/* Links inside a sentence need more than a change of shade to be found. */
.footer-credits--byline a {
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.5);
  text-underline-offset: 2px;
}

.footer-credits--legal {
  display: flex;
  gap: 1.25rem;
}

@media (min-width: 640px) {
  .team {
    grid-template-columns: repeat(2, 1fr);
  }

  .footer-sitemap {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 768px) {
  .footer-sitemap {
    grid-template-columns: 1.5fr 1fr 1fr;
    gap: 3rem;
  }

  .footer-colophon {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
  }

  .footer-credits {
    width: 100%;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
  }

  .footer-credits--byline {
    margin-bottom: 0;
  }
}

@media (min-width: 1120px) {
  .team {
    grid-template-columns: repeat(3, 1fr);
  }

}

/* The footer sits inside the deck's last slide, which scrolls on its own, so
   it needs no top margin there. It also has to reach the edges: the slide is
   inside the padded main container, which would otherwise leave a strip of
   page either side of it. */
.slides--slide__extra .footer {
  margin-top: 0;
  margin-left: calc(-1 * var(--container-padding, 0px));
  margin-right: calc(-1 * var(--container-padding, 0px));
}

/* Tradition articles
   Long-form reading pages, not the slide deck the place articles use. The
   body HTML comes from the old site and carries its own title, metadata and
   a twelve column grid, so the grid classes it expects are rebuilt here with
   CSS Grid rather than the float system the original used. */

.tradition-page .main-container {
  --container-padding: 0px;
  max-width: 1920px;
  padding: 0;
}

.wrapper,
.wrapper-full {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: 2rem;
}

.wrapper {
  max-width: 68rem;
  margin: 0 auto;
  padding: 0 1.5rem;
}

.wrapper-full {
  column-gap: 0;
}

/* The original grid let any child without a span class fill the row, so the
   same default has to be explicit here. The span rules below override it. */
.wrapper > *,
.wrapper-full > * {
  grid-column: span 12;
}

.span-12 { grid-column: span 12; }

@media (min-width: 640px) {
  .span-tablet-4 { grid-column: span 4; }
  .span-tablet-5 { grid-column: span 5; }
  .span-tablet-6 { grid-column: span 6; }
  .span-tablet-7 { grid-column: span 7; }
  .span-tablet-8 { grid-column: span 8; }
}

/* The intro is pulled up over the opening photo, fading into it. */
.article-tradition__intro {
  background-color: var(--color-black);
  color: var(--color-white);
  padding: 1rem 0;
}

.article-tradition__title {
  color: var(--color-white);
  text-transform: uppercase;
  font-size: var(--step-6);
  margin-bottom: 0;
}

.article-tradition__metadata {
  text-transform: uppercase;
  font-size: 0.7rem;
  font-weight: 300;
  line-height: 1;
}

.article-tradition__intro p {
  color: rgba(255, 255, 255, 0.85);
}

.article-tradition__body {
  color: var(--color-grey-700);
  font-weight: 300;
  margin-top: 2rem;
}

.article-tradition__body .responsive-image {
  margin-bottom: 1rem;
}

.article-tradition__gallery .responsive-image {
  margin-bottom: 0;
}

.article-tradition__highlight {
  font-size: clamp(1.0625rem, 0.9rem + 0.7vw, 1.5rem);
  font-style: italic;
  text-align: center;
  font-weight: 300;
}

.article-tradition__quote {
  font-size: clamp(1.25rem, 0.9rem + 1.6vw, 2.5rem);
  font-style: italic;
  text-align: center;
  font-weight: 300;
  margin: 3rem 0;
}

.article-tradition__quote::before {
  content: "«";
  color: var(--color-grey-400);
}

.article-tradition__quote::after {
  content: "»";
  color: var(--color-grey-400);
}

.article-tradition__question {
  font-style: italic;
  font-size: 1.2rem;
  color: var(--color-grey-800);
}

.article-tradition__border {
  border-top: 1px solid var(--color-grey-200);
  border-bottom: 1px solid var(--color-grey-300);
}

.article-tradition__separator {
  margin: 1rem 0;
}

.article-tradition__full-image-with-text,
.article-tradition__closing {
  position: relative;
}

.article-tradition__closing-text,
.article-tradition__full-image-with-text-text {
  background-color: var(--color-grey-800);
  color: var(--color-white);
  padding-top: 1rem;
}

/* These sit over a photo, so their text has to beat the global paragraph
   colour rather than inherit it. */
.article-tradition__closing-text p,
.article-tradition__closing-text strong,
.article-tradition__full-image-with-text-text p,
.article-tradition__full-image-with-text-text strong {
  color: var(--color-white);
}

/* The closing photo ends the page, so it keeps none of the body photos'
   bottom margin, which showed as a grey strip under the overlay. */
.article-tradition__body .article-tradition__closing .responsive-image {
  margin-bottom: 0;
}

@media (min-width: 640px) {
  /* The gradient covers the 25rem the intro pulls up over the photo; a long
     intro runs on below the photo, and there it is plain black, where the
     gradient's last, not quite opaque stretch showed the white page as a
     grey strip. */
  .article-tradition__intro {
    background:
      linear-gradient(to bottom, transparent 0%, transparent 10%, rgba(0, 0, 0, 0.6) 50%, rgba(0, 0, 0, 1) 100%) top / 100% 25rem no-repeat,
      linear-gradient(#000, #000) 0 25rem / 100% 100% no-repeat;
    margin-top: -25rem;
    /* Matching the pull-up makes the intro end exactly where the opening
       photo does. The original computed this in JavaScript. */
    min-height: 25rem;
    padding: 0 0 2rem;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
  }

  /* Past 1920px the page stops widening and the opening photo with it; the
     window either side of it goes black, as the photo's own edges and the
     intro's gradient do, so the opening reads as one frame. The rest of the
     article keeps the white page. */
  .artile-tradition__container > .responsive-image:first-child,
  .artile-tradition__container > .article-tradition__intro {
    box-shadow: 0 0 0 100vmax #000;
    clip-path: inset(0 -100vmax);
  }

  /* The closing photo gets the same: black either side past 1920px. */
  .article-tradition__closing {
    box-shadow: 0 0 0 100vmax #000;
    clip-path: inset(0 -100vmax);
  }

  /* Where the black shows, the photos' sides fade into it rather than end
     on a hard edge. The closing text stays over the fade. */
  @media (min-width: 1920px) {
    .artile-tradition__container > .responsive-image:first-child,
    .article-tradition__closing .responsive-image {
      position: relative;
    }

    .artile-tradition__container > .responsive-image:first-child::after,
    .article-tradition__closing .responsive-image::after {
      content: "";
      position: absolute;
      inset: 0;
      background: linear-gradient(to right, #000, transparent 12%, transparent 88%, #000);
    }

    .article-tradition__closing-text {
      z-index: 1;
    }
  }

  .article-tradition__metadata {
    font-size: 1rem;
  }

  .article-tradition__body {
    margin-top: 4rem;
  }

  .article-tradition__separator {
    margin: 4rem 0;
  }

  .article-tradition__full-image-with-text-text {
    background: linear-gradient(to bottom, rgba(17, 17, 17, 1) 0%, rgba(17, 17, 17, 1) 50%, rgba(17, 17, 17, 0.6) 80%, transparent 100%);
    color: var(--color-white);
    padding-top: 4rem;
    position: absolute;
    top: 0;
    z-index: 1;
    width: 100%;
  }

  .article-tradition__full-image-with-text-image {
    padding-top: 10rem;
  }

  .article-tradition__closing-text {
    background-color: rgba(0, 0, 0, 0.5);
    bottom: 0;
    font-size: 1.5rem;
    padding-top: 10rem;
    position: absolute;
    top: 0;
    width: 100%;
  }
}

@media (min-width: 1120px) {
  .article-tradition__intro {
    margin-top: -40rem;
    min-height: 40rem;
  }

  .article-tradition__metadata {
    font-size: 1.5rem;
  }

  .article-tradition__body .responsive-image {
    margin-bottom: 2rem;
  }

  .article-tradition__quote {
    margin: 6rem 0;
  }

  .article-tradition__closing-text {
    padding-top: 15rem;
  }
}

/* Closing block of an article */

/* The closing block sits on the same light purple as the titles, the width
   of the window, which sets it apart from the article above. */
.article-extra {
  background-color: var(--color-primary-tint);
  box-shadow: 0 0 0 100vmax var(--color-primary-tint);
  clip-path: inset(0 -100vmax);
  width: 100%;
}

/* No side padding of its own: below the deck the page's column already has
   it, and the photos above run to its edges. */
.article-extra--wrapper {
  max-width: 68rem;
  margin: 0 auto;
  padding: 2rem 0 3rem;
}

/* Side by side once there is room: the map on the left over three of the
   four columns the related cards take below, the summary on the right over
   the fourth, on the same grid so their edges line up.
   Only on the deck, where the block takes the site's full width: in the
   stacked page's 60rem column the summary would be too narrow to read. */
@media (min-width: 1280px) {
  .article-extra--wrapper {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    column-gap: 2rem;
    align-items: start;
  }

  .extra-arrive {
    grid-area: 1 / 1 / 2 / 4;
  }

  .extra-summary {
    grid-area: 1 / 4 / 2 / 5;
  }

  .extra-related {
    grid-column: 1 / -1;
  }
}

/* Each block opens on a purple rule with a small label, as the regions
   index does, so the map, the summary and the cards carry the weight and
   the labels only name them. */
.extra-block {
  margin-bottom: 3rem;
  border-top: 3px solid var(--color-primary);
  padding-top: 1rem;
}

.extra-block--title {
  font-weight: 700;
  color: var(--color-primary);
  text-transform: uppercase;
  font-size: var(--step-1);
  letter-spacing: 0.04em;
  margin: 0 0 1rem;
}

/* The related articles are a section of their own, set further apart. */
.extra-related {
  margin-top: 1rem;
}

/* The summary, and the note on why a place has no map, read a size up as
   plain paragraphs: the block's rule and label frame them. */
.extra-block--notice,
.extra-summary p {
  font-size: var(--step-1);
  line-height: 1.65;
  color: var(--color-grey-900);
}

/* The map with its "view on Google Maps" button over the top right corner,
   clear of the zoom on the left and the attribution below. Isolated, so
   Leaflet's own layers stay under the fixed header when it scrolls past. */
.extra-map--frame {
  position: relative;
  isolation: isolate;
}

.extra-map--expand {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 1001;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.4);
}

/* On a phone the map is short, so the button keeps small. */
@media (max-width: 639px) {
  .button.extra-map--expand {
    padding: 0.3rem 0.75rem;
    font-size: 0.8125rem;
  }
}

.extra-map {
  aspect-ratio: 16 / 9;
  border-radius: 4px;
  background-color: var(--color-grey-200);
}

.button {
  display: inline-block;
  background-color: var(--color-primary);
  color: var(--color-white);
  padding: 0.5rem 1.125rem;
  border-radius: 4px;
  font-size: 0.9375rem;
}

.button:hover {
  background-color: var(--color-primary-75);
  color: var(--color-white);
  text-decoration: none;
}

@media (min-width: 1280px) {
  /* The closing block is taller than a screen, so it is the one slide that
     scrolls inside itself instead of snapping. */
  .slides--slide__extra {
    height: auto;
    min-height: 100vh;
    overflow-y: auto;
    background-color: var(--color-primary-tint);
    display: flex;
    flex-direction: column;
  }

  /* Articles with no geolocation have a short closing block, which left the
     footer stranded mid-screen with white below it. */
  .slides--slide__extra .footer {
    margin-top: auto;
  }

  /* The width of the rest of the site, the header's and the footer's,
     now that the block runs in two columns. */
  .article-extra--wrapper {
    max-width: 1920px;
    box-sizing: border-box;
    padding: 3rem 2rem 4rem;
  }
}

/* Maps
   OpenStreetMap's tiles carry far more colour and labelling than the flat
   basemap this design was built around, which drowned the purple overlays.
   Washing them out restores the quiet backdrop they need. */

/* Leaflet stacks its panes and controls up to z-index 1000, the fixed
   header's own, so a map further down the page painted its zoom buttons
   over the open header menu. Each map keeps its layers to itself. */
.leaflet-container {
  isolation: isolate;
}

/* The zoom buttons and the popup's close button are links, and the site's
   a:hover, loaded after Leaflet's stylesheet, underlined their symbols. */
.leaflet-bar a:hover,
.leaflet-container a.leaflet-popup-close-button:hover {
  text-decoration: none;
}

/* Leaflet writes the zoom symbols as text in a monospace font, whose + and
   − sit a few pixels low and right, by a different amount on each system.
   Drawn as two bars instead, they are centred exactly; the link keeps its
   accessible name. */
.leaflet-bar a.leaflet-control-zoom-in,
.leaflet-bar a.leaflet-control-zoom-out {
  position: relative;
  text-indent: 0;
}

.leaflet-control-zoom-in span,
.leaflet-control-zoom-out span {
  visibility: hidden;
}

.leaflet-control-zoom-in::before,
.leaflet-control-zoom-in::after,
.leaflet-control-zoom-out::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 12px;
  height: 2px;
  background-color: currentColor;
  transform: translate(-50%, -50%);
}

.leaflet-control-zoom-in::after {
  width: 2px;
  height: 12px;
}

.leaflet-tile-pane {
  filter: grayscale(1) contrast(0.55) brightness(1.22);
}

.leaflet-container .leaflet-control-attribution {
  background: rgba(255, 255, 255, 0.8);
  font-size: 0.6875rem;
}

/* Locality pages
   The map runs edge to edge, as it did in the original, where it sat outside
   the wrapper. So the container drops its padding and its cap — a cap would
   stop the map at 1920px and leave strips of page either side on a wider
   screen — and the blocks around the map carry their own measure, the same
   way the home page is built. */

body.locality-page .main-container {
  --container-padding: 0px;
  max-width: none;
  padding: 0;
  /* Still clear of the fixed header. */
  padding-top: 6rem;
}

.locality-wrapper {
  margin: 0 auto;
  max-width: 1920px;
  padding: 0 2rem;
}

.locality-map {
  /* The 500px of the original, which is a lot of phone, so it gives way
     below the first breakpoint. */
  height: 31.25rem;
  margin: 2rem 0;
  background-color: var(--color-grey-200);
}

/* Straight under the title's band, with no strip of white between. */
.locality-wrapper:has(+ .locality-map, + .localities-section) > .page-header:last-child {
  margin-bottom: 0;
}

.locality-wrapper:has(> .page-header:last-child) + .locality-map {
  margin-top: 0;
}

/* A full-width block that ends the page meets the footer, with no strip of
   white between: the explorer's map, the localities index's list over its
   map, a tradition's closing photo. */
.main-container > :is(.locality-map, .localities-section, .article-tradition):last-child {
  margin-bottom: 0;
}

.main-container:has(> :is(.locality-map, .localities-section, .article-tradition):last-child) + .footer {
  margin-top: 0;
}

@media (max-width: 768px) {
  .locality-map {
    height: 20rem;
  }
}

/* The localities index: the home list over the map, under a lead. */

.localities-lead {
  max-width: 52rem;
  margin: 0 auto 2.5rem;
  text-align: center;
  color: var(--color-white);
}

/* The regions index: one block per region, its municipalities under it. */

.regions-lead {
  max-width: 52rem;
  margin-bottom: 3rem;
}

.regions-index {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
  gap: 2.5rem 2rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 1280px) {
  .regions-index {
    grid-template-columns: repeat(5, 1fr);
  }
}

.regions-index--item {
  border-top: 3px solid var(--color-primary);
  padding-top: 1rem;
}

.regions-index--title {
  margin: 0;
  font-size: var(--step-2);
}

.regions-index--title a {
  color: var(--color-primary);
}

.regions-index--count {
  margin: 0.25rem 0 1rem;
  color: var(--color-grey-600);
  font-size: 0.95rem;
}

.regions-index--localities {
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--color-grey-700);
  font-size: 0.95rem;
  line-height: 1.8;
}

.regions-index--localities a {
  color: var(--color-primary);
}

/* The explorer map: two filters over a map that takes most of the screen,
   as the original's full-height one did. */

/* The filters sit in the title's band, as part of the map's header: the
   band runs on under the title, and the map starts where it ends. */
.explorer-page .page-header {
  margin-bottom: 0;
  padding-bottom: 0.75rem;
}

.explorer-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 1rem 1.5rem;
  padding-bottom: 1.5rem;
  background-color: var(--color-primary-tint);
  box-shadow: 0 0 0 100vmax var(--color-primary-tint);
  clip-path: inset(0 -100vmax);
}

.explorer-page .locality-wrapper + .explorer-map {
  margin-top: 0;
}

.explorer-filters--field {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  flex: 1 1 16rem;
  min-width: 0;
  max-width: 22rem;
}

.explorer-filters--field label {
  font-size: var(--step--1);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-primary);
}

/* Drawn by hand: Safari's native select ignores padding and height, which
   left these thinner than anything else on the page. */
.explorer-filters--field select {
  /* A long category name would otherwise widen the field past the screen. */
  width: 100%;
  min-width: 0;
  height: 2.75rem;
  appearance: none;
  font: inherit;
  padding: 0 2.5rem 0 1rem;
  border: 2px solid var(--color-primary-60);
  border-radius: 6px;
  background: var(--color-white) 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 1.5l5 5 5-5' fill='none' stroke='%23423780' stroke-width='2'/%3E%3C/svg%3E") no-repeat right 1rem center;
  color: var(--color-grey-800);
  cursor: pointer;
}

.explorer-filters--field select:hover {
  border-color: var(--color-primary);
}

.explorer-filters--field select:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* Level with the fields, not with their labels. */
.explorer-filters--status {
  display: flex;
  align-items: center;
  height: 2.75rem;
  margin: 0;
  color: var(--color-grey-700);
  font-size: 0.95rem;
}

.locality-map.explorer-map {
  height: 75vh;
  min-height: 24rem;
}

/* The marker popups, as the original drew them: the teaser photo edge to
   edge, the title on a purple band under it, the tip in the same purple and
   the close button in white over the photo. The whole thing is a link. */

.leaflet-popup-content-wrapper {
  padding: 0;
  border-radius: 5px;
  overflow: hidden;
}

.leaflet-container .leaflet-popup-content {
  margin: 0;
  line-height: 1.3;
}

.leaflet-popup-tip {
  background-color: var(--color-primary);
}

.leaflet-container a.leaflet-popup-close-button,
.leaflet-container a.leaflet-popup-close-button:hover {
  width: 28px;
  height: 28px;
  font-size: 24px;
  line-height: 28px;
  color: var(--color-white);
  text-shadow: 0 0 4px rgba(0, 0, 0, 0.7);
}

/* On a phone the popup is as wide as the map and would slide under the
   zoom buttons, which Leaflet keeps above every pane. */
@media (max-width: 639px) {
  .leaflet-container:has(.leaflet-popup) .leaflet-control-zoom {
    visibility: hidden;
  }
}

.leaflet-popup-content a {
  display: block;
}

.leaflet-popup-content a:hover {
  text-decoration: none;
}

.leaflet-popup-content img {
  display: block;
  width: 100%;
  height: auto;
}

.leaflet-popup-content h2 {
  margin: 0;
  padding: 0.5rem 0.75rem;
  background-color: var(--color-primary);
  color: var(--color-white);
  font-size: 1rem;
  text-transform: uppercase;
}

.leaflet-popup-content a:hover h2,
.leaflet-popup-content a:focus-visible h2 {
  background-color: var(--color-primary-75);
}
