@charset "UTF-8";
/* Generated from scss/. Do not edit — run `npm run build:css`. */
/* Design tokens and webfaces. Everything the site draws with is declared here.
   Dark mode is a value swap on [data-theme="dark"] — no component knows about it. */
/* ---------------------------------------------------------------- webfaces */
@font-face {
  font-family: "PP Neue Montreal";
  font-weight: 300;
  font-style: normal;
  font-display: block;
  src: url("../fonts/PPNeueMontreal-Light.otf") format("opentype");
}
@font-face {
  font-family: "PP Neue Montreal";
  font-weight: 400;
  font-style: normal;
  font-display: block;
  src: url("../fonts/PPNeueMontreal-Regular.otf") format("opentype");
}
@font-face {
  font-family: "PP Neue Montreal";
  font-weight: 400;
  font-style: italic;
  font-display: block;
  src: url("../fonts/PPNeueMontreal-Italic.otf") format("opentype");
}
@font-face {
  font-family: "PP Neue Montreal";
  font-weight: 600;
  font-style: normal;
  font-display: block;
  src: url("../fonts/PPNeueMontreal-Semibold.otf") format("opentype");
}
@font-face {
  font-family: "PP Neue Montreal";
  font-weight: 700;
  font-style: normal;
  font-display: block;
  src: url("../fonts/PPNeueMontreal-Extrabold.otf") format("opentype");
}
@font-face {
  font-family: "PP Neue Montreal";
  font-weight: 800;
  font-style: normal;
  font-display: block;
  src: url("../fonts/PPNeueMontreal-Extrabold.otf") format("opentype");
}
@font-face {
  font-family: "PP Museum";
  font-weight: 300;
  font-style: normal;
  font-display: block;
  src: url("../fonts/PPMuseum-Light.otf") format("opentype");
}
@font-face {
  font-family: "PP Museum";
  font-weight: 400;
  font-style: normal;
  font-display: block;
  src: url("../fonts/PPMuseum-Regular.otf") format("opentype");
}
@font-face {
  font-family: "PP Museum";
  font-weight: 800;
  font-style: normal;
  font-display: block;
  src: url("../fonts/PPMuseum-Ultrabold.otf") format("opentype");
}
@font-face {
  font-family: "PP NeueBit";
  font-weight: 700;
  font-style: normal;
  font-display: block;
  src: url("../fonts/PPNeueBit-Bold.otf") format("opentype");
}
@font-face {
  font-family: "PP Editorial Old";
  font-weight: 200;
  font-style: normal;
  font-display: block;
  src: url("../fonts/PPEditorialOld-Ultralight.otf") format("opentype");
}
@font-face {
  font-family: "PP Editorial Old";
  font-weight: 200;
  font-style: italic;
  font-display: block;
  src: url("../fonts/PPEditorialOld-UltralightItalic.otf") format("opentype");
}
@font-face {
  font-family: "PP Editorial Old";
  font-weight: 400;
  font-style: normal;
  font-display: block;
  src: url("../fonts/PPEditorialOld-Regular.otf") format("opentype");
}
@font-face {
  font-family: "PP Editorial Old";
  font-weight: 400;
  font-style: italic;
  font-display: block;
  src: url("../fonts/PPEditorialOld-Italic.otf") format("opentype");
}
@font-face {
  font-family: "PP Editorial Old";
  font-weight: 800;
  font-style: normal;
  font-display: block;
  src: url("../fonts/PPEditorialOld-Ultrabold.otf") format("opentype");
}
@font-face {
  font-family: "PP Editorial Old";
  font-weight: 800;
  font-style: italic;
  font-display: block;
  src: url("../fonts/PPEditorialOld-UltraboldItalic.otf") format("opentype");
}
@font-face {
  font-family: "Monaspace Neon";
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
  src: url("../fonts/MonaspaceNeonVar.woff2") format("woff2-variations");
}
@font-face {
  font-family: "Monaspace Neon";
  font-weight: 400;
  font-style: italic;
  font-display: swap;
  src: url("../fonts/MonaspaceNeon-Italic.woff2") format("woff2");
}
/* ------------------------------------------------------------------ tokens */
:root {
  /* Surfaces and ink. Every one of these flips in dark mode. */
  --paper: #f4f4f4;
  --bg2: #eaeae9;
  --bg4: #a1a19e; /* the echo, the part of a title that runs past its row */
  --bg-inv: #2e2d2c;
  --ink: #171716;
  --ink2: #454442;
  --mut: #5c5b59;
  --faint: #a1a19e;
  --hair: #e2e2e1;
  --red: #e75800;
  --duo-shadow: #7f2600;
  --duo-highlight: #e75800;
  /* The ink that sits on the duotone wash. The wash is identical in both themes,
     so this does not flip with them. White is the only value that holds across
     the whole map: against the shadow end it reads 9.6:1 and against the
     highlight 3.6:1, where a dark ink manages 1.7:1 over the shadows and
     disappears into exactly the part of a photograph there is most of. */
  --duo-ink: #ffffff;
  /* The plate that holds a mark rather than a photograph. A mark was drawn for a
     light ground, so its plate keeps one in both themes: one value, no dark
     override. Nothing is drawn on it — the label sits under the plate, on the
     page ground, where --mut is legible in both themes. */
  --plate-ground: #f4f4f4;
  /* Type scale. Fluid between a 320px and a 1560px viewport. */
  --size-xs: clamp(0.6914rem, 0.6899rem + 0.0065vw, 0.6944rem);
  --size-sm: clamp(0.7778rem, 0.7522rem + 0.1163vw, 0.8333rem);
  --size-base: clamp(0.875rem, 0.8174rem + 0.2618vw, 1rem);
  --size-lg: clamp(0.9844rem, 0.885rem + 0.4516vw, 1.2rem);
  --size-xl: clamp(1.1074rem, 0.9542rem + 0.6965vw, 1.44rem);
  --size-4xl: clamp(1.5768rem, 1.1568rem + 1.909vw, 2.4883rem);
  --size-5xl: clamp(1.7739rem, 1.2154rem + 2.5384vw, 2.986rem);
  --leading-tight: 1.2;
  --leading-normal: 1.5;
  --leading-responsive: calc(1em + 0.5rem);
  --leading-display: calc(1em + 0.1rem);
  --track-tight: -0.025em;
  /* Space scale, same fluid ramp. */
  --space-4xs: clamp(0.125rem, 0.125rem + 0vw, 0.125rem);
  --space-3xs: clamp(0.25rem, 0.25rem + 0vw, 0.25rem);
  --space-2xs: clamp(0.4375rem, 0.4087rem + 0.1309vw, 0.5rem);
  --space-xs: clamp(0.6875rem, 0.6587rem + 0.1309vw, 0.75rem);
  --space-s: clamp(0.875rem, 0.8174rem + 0.2618vw, 1rem);
  --space-m: clamp(1.3125rem, 1.2261rem + 0.3927vw, 1.5rem);
  --space-l: clamp(1.75rem, 1.6348rem + 0.5236vw, 2rem);
  --space-xl: clamp(2.625rem, 2.4522rem + 0.7853vw, 3rem);
  --space-2xl: clamp(3.5rem, 3.2696rem + 1.0471vw, 4rem);
  --space-3xl: clamp(5.25rem, 4.9045rem + 1.5707vw, 6rem);
  --space-xl-2xl: clamp(2.625rem, 1.9915rem + 2.8796vw, 4rem);
  /* The measure. Content stops at 1560px and the surplus becomes the gutter. */
  --measure: 1560px;
  --gutter: max(var(--space-m), calc((100% - var(--measure)) / 2));
  /* Breakpoints, emitted from the map in scss/_breakpoints.scss so that
     js/site.js reads exactly the widths the media queries were compiled with.
     See window.SITE.media(). */
  --bp-narrow: 860px;
  --bp-stack: 560px;
  /* The narrowest a colophon column may get before the grid drops a track. */
  --col-min: 22rem;
  /* Face stacks. The display faces are picked per entry by js/fit.js. */
  --font-sans: "PP Neue Montreal", Helvetica, Arial, sans-serif;
  --font-serif: "PP Editorial Old", Georgia, serif;
  --font-mono: "Monaspace Neon", ui-monospace, SFMono-Regular, Menlo, monospace;
  /* The five-track grid the index rows and the colophon rows both sit on.
     The floor is wrapped in min(…, 100%) so it cannot exceed the container: a bare
     fixed floor keeps applying when the container is narrower than it, and the
     track overflows instead of shrinking. auto-fit hides this at a default root
     size by dropping tracks, but 10rem is 10rem — at a large user font-size on a
     narrow viewport a single track is already wider than the page. */
  --track: minmax(min(max(10rem, calc((100% - 4 * var(--space-m)) / 5)), 100%), 1fr);
}

/* Tell the UA which way the page is set. The theme is a data-theme swap, so the
   browser has no other way to know: without this the scrollbar, the overscroll
   canvas behind body and any UA control stay in light chrome against a #20201f
   page — a white gutter flashing on every rubber-band scroll. */
:root {
  color-scheme: light;
}

[data-theme=dark] {
  color-scheme: dark;
}

[data-theme=dark] {
  --paper: #20201f;
  --bg2: #282726;
  --bg4: #5b5a57;
  --bg-inv: #e2e1e0;
  --ink: #ffffff;
  --ink2: #bfbebd;
  --mut: #9f9f9c;
  --faint: #5b5a57;
  --hair: #2e2d2c;
  /* Light ink on a dark ground bleeds optically, so the accent steps down rather
     than the weight — a static family has no grade axis, and this costs no reflow. */
  --red: #e15400;
}

/* Paper is paper. Browsers do not print background colours by default, so a page
   printed while the dark theme is on sent white ink to a sheet that never received
   its dark ground: the titles landed at about 2.3:1 on white and the page came out
   all but blank. Print always uses the light values, whatever the screen is set to. */
@media print {
  :root,
  [data-theme=dark] {
    color-scheme: light;
    --paper: #ffffff;
    --bg2: #eaeae9;
    --bg4: #a1a19e;
    --bg-inv: #2e2d2c;
    --ink: #171716;
    --ink2: #454442;
    --mut: #5c5b59;
    --faint: #a1a19e;
    --hair: #e2e2e1;
    --red: #e75800;
  }
}
/* Reset, document defaults, and the rules that apply to every page. */
*, *::before, *::after {
  box-sizing: border-box;
}

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

body {
  margin: 0;
  padding: 0;
  min-height: 100vh;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--size-base);
  -webkit-font-smoothing: antialiased;
}

a {
  color: inherit;
  text-decoration: none;
}

::selection {
  background: var(--red);
  color: var(--paper);
}

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

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

/* Present to the accessibility tree, absent from the page. For the one heading a
   page needs but does not draw — the index names itself in the masthead and in the
   nav, and setting that word a third time in the page body would be noise. */
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Skipped past by everything except the keyboard. */
.skip {
  position: absolute;
  left: var(--space-m);
  top: var(--space-m);
  z-index: 100;
  padding: var(--space-2xs) var(--space-s);
  background: var(--paper);
  border: 1px solid var(--red);
  color: var(--red);
  transform: translateY(-200%);
}

.skip:focus {
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
/* The apparatus: every label, caption, number and control on the site. It is the
   machinery around the work — never the work itself, which is why it is all one
   mono face at one size, and why it is the only thing that ever sets in accent. */
.mono {
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: var(--size-xs);
  letter-spacing: 0;
  font-feature-settings: "calt" 1, "liga" 1, "dlig" 1, "ss01" 1, "ss02" 1, "ss03" 1, "ss04" 1, "ss05" 1, "ss06" 1, "ss07" 1, "ss08" 1;
  font-variant-ligatures: common-ligatures discretionary-ligatures contextual;
}

.caps {
  text-transform: uppercase;
}

.btn {
  appearance: none;
  border: 1px solid var(--hair);
  background: transparent;
  color: var(--mut);
  font: inherit;
  letter-spacing: 0;
  text-transform: uppercase;
  padding: var(--space-3xs) var(--space-2xs);
  cursor: pointer;
}

.btn:hover {
  border-color: var(--red);
  color: var(--red);
}

.link:hover {
  color: var(--red);
}

/* The theme switch names the theme it would take you to — "Dark" while light,
   "Light" while dark. Both labels are in the markup and CSS picks one, so the
   right word is up at first paint with no flash and no work for JS. */
[data-theme=dark] [data-if-light] {
  display: none;
}

html:not([data-theme=dark]) [data-if-dark] {
  display: none;
}

/* The persistent chrome on every page: the sticky header and the footer. */
.masthead {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  background: var(--paper);
}

/* Name left, links right, and they only break to a second line when they would
   genuinely collide — flex decides that from the actual text, so there is no
   breakpoint to keep in sync with the length of the nav. */
.masthead__inner {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--space-2xs) var(--space-l);
  padding: var(--space-m) var(--gutter) var(--space-2xs);
}

.masthead__name {
  font-weight: 700;
  font-size: var(--size-xl);
  line-height: var(--leading-responsive);
  letter-spacing: var(--track-tight);
}

.masthead__nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-s);
  color: var(--mut);
}

.masthead__nav [aria-current=page] {
  color: var(--red);
}

.masthead__rule {
  height: 1px;
  background: var(--hair);
}

@media print {
  .masthead {
    display: none;
  }
}
/* --------------------------------------------------------------------- footer */
.footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-s) var(--space-l);
  padding: var(--space-l) var(--gutter) var(--space-2xl);
  border-top: 1px solid var(--hair);
  color: var(--mut);
}

/* Opt this document into transitioning on same-origin navigation. Both the page
   being left and the page being entered have to carry this, which is why it sits
   in a shared partial rather than a page one. */
@view-transition {
  navigation: auto;
}
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 500ms;
  animation-timing-function: ease-in-out;
}

/* The masthead and footer are deliberately NOT given a view-transition-name.
 *
 * Naming them holds them still through the fade, which looks right in Chrome —
 * but in WebKit a named `position: sticky` element paints as a blank gap for the
 * whole transition, so the header simply vanishes and comes back. Verified in
 * WebKit 26.5: with the masthead named it is empty mid-transition; with the name
 * removed it renders correctly and the crossfade still runs.
 *
 * Nothing is lost by dropping it. The chrome is identical on both pages, so
 * cross-fading it against itself is invisible — the only part that differs is
 * which nav item is marked current, and fading that is the nicer result anyway.
 */
@media (prefers-reduced-motion: reduce) {
  /* Swap outright rather than cross-fade. The navigation still works; it simply
     does not animate. */
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none;
  }
}
/* Shared text roles and the specification list. Used by entry pages and the
   colophon — both are records of the same shape: a thing, when, and a note. */
.strong {
  font-size: var(--size-sm);
  line-height: var(--leading-normal);
  font-weight: 600;
}

.years {
  line-height: var(--leading-normal);
  color: var(--mut);
}

.note {
  font-size: var(--size-sm);
  line-height: var(--leading-normal);
  font-weight: 400;
  color: var(--ink2);
  text-wrap: pretty;
}

.spec {
  margin: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-3xs) var(--space-s);
  line-height: var(--leading-normal);
  color: var(--mut);
  border-top: 1px solid var(--hair);
  padding-top: var(--space-xs);
}

.spec dt {
  text-align: right;
  text-transform: uppercase;
  color: var(--faint);
}

.spec dd {
  margin: 0;
  text-align: left;
}

/* The one row that goes somewhere. Nothing else in the list is clickable, and the
   site's links are undecorated, so the arrow is what says so. It is sized in em
   and sat on the baseline, which keeps it with the word rather than with the row. */
.spec__out {
  width: 0.7em;
  height: 0.7em;
  margin-left: 0.35em;
  vertical-align: baseline;
}

.listing {
  display: grid;
  grid-template-columns: repeat(auto-fit, var(--track));
  column-gap: var(--space-m);
  row-gap: var(--space-3xs);
  align-items: start;
  border-top: 1px solid var(--hair);
  padding: var(--space-s) 0;
  min-height: 3.5em;
}

.listing .note {
  grid-column: 2/-1;
}

/* See css/colophon.css: at this width the grid is down to two tracks and the
   record stacks. The span must be reset with the tracks or it lands in an
   implicit column off the side of the page. */
@media (max-width: 560px) {
  .listing {
    grid-template-columns: minmax(0, 1fr);
  }
  .listing .note {
    grid-column: 1/-1;
  }
}
/* An entry: plates on the left, the reading column on the right. */
.entry {
  padding: var(--space-2xl) var(--gutter) var(--space-3xl);
}

.entry__grid {
  display: grid;
  /* min(300px, 100%) rather than a bare 300px: a fixed floor still applies when the
     container is narrower than it, so the track overflows instead of shrinking. The
     narrow block below drops to one column well above 300px, which hides the problem
     rather than removing it — a wide root font-size or a nested container brings it
     straight back. */
  grid-template-columns: minmax(0, 1.42fr) minmax(min(300px, 100%), 0.58fr);
  gap: var(--space-xl-2xl);
}

/* Most entries have no images yet. Rather than hold an empty plate column open,
   the reading column takes the page and stops at its own measure. */
.entry__grid--unplated {
  grid-template-columns: minmax(0, 1fr);
  max-width: 68ch;
}

.plates {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xl);
}

.plate {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}

.plate__img {
  width: 100%;
  aspect-ratio: var(--ratio);
  background-size: cover;
  background-position: center;
}

/* Caption left, figure number right, both flush with the edges of the plate above.
   The number is pushed over rather than seated by `space-between`, so it holds the
   right on a plate that has no caption beside it. Only the caption takes the 56ch
   measure: the number is one short line and would never reach it. */
.plate__note {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2xs) var(--space-m);
  line-height: var(--leading-normal);
  color: var(--mut);
}

.plate__caption {
  max-width: 56ch;
}

.plate__label {
  margin-left: auto;
  text-align: right;
}

/* A mark is not a photograph: it must not be cropped, and it was drawn for a light
   ground, so its plate keeps one in both themes. The padding is what insets the
   mark from the edge of that ground, since the background is origined to the
   content box — a photograph runs to its edges with nothing drawn around it. */
.plate__img--contain {
  background-size: contain;
  background-repeat: no-repeat;
  background-origin: content-box;
  background-color: var(--plate-ground);
  padding: var(--space-l);
}

.entry__aside {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
}

.entry__title {
  margin: 0;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-m);
  font-family: var(--font-sans);
  font-size: var(--size-xl);
  line-height: var(--leading-responsive);
  letter-spacing: var(--track-tight);
  font-weight: 700;
  text-wrap: pretty;
}

.entry__num {
  flex: none;
  line-height: var(--leading-normal);
  color: var(--red);
}

.entry__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
  font-size: var(--size-sm);
  line-height: var(--leading-normal);
  font-weight: 400;
  max-width: 62ch;
  text-wrap: pretty;
}

.entry__body p {
  margin: 0;
}

/* The standfirst a note opens with, where it has one. It is also what the index
   row quotes, so the two read as the same sentence. */
.entry__lead {
  font-size: var(--size-lg);
  line-height: var(--leading-responsive);
  letter-spacing: var(--track-tight);
  font-weight: 600;
  text-wrap: balance;
}

/* A labelled list inside a note — the term carries the weight, the description
   hangs under it rather than beside it, so long descriptions keep the measure. */
.entry__list {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.entry__list dt {
  font-weight: 600;
}

.entry__list dd {
  margin: 0;
  color: var(--ink2);
}

/* An entry that exists in the sequence but has no note behind it yet. */
.entry__pending {
  color: var(--faint);
}

.entry__nav {
  display: flex;
  justify-content: space-between;
  gap: var(--space-s);
  padding-top: var(--space-2xs);
}

@media (max-width: 860px) {
  .entry__grid {
    grid-template-columns: minmax(0, 1fr);
  }
}
