/* Mat's website. Written by hand from docs/website/design/tokens.css and the screens in
   docs/website/design/screens; the rules are docs/website/HANDOFF.md.

   Three shapes of window:
   - wide: desktop and tablet (the default rules here);
   - narrow: a phone held upright, (max-width: 700px) and (min-height: 500px), or anything
     480px wide or less;
   - short: a phone on its side, (max-height: 499px) and (min-width: 481px) and landscape.
   Layouts follow the space given, never the kind of device. */

@font-face {
  font-family: 'Newsreader';
  src: url('fonts/Newsreader-Roman.woff2') format('woff2');
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
}
@font-face {
  font-family: 'Newsreader';
  src: url('fonts/Newsreader-Italic.woff2') format('woff2');
  font-style: italic;
  font-weight: 200 800;
  font-display: swap;
}
@font-face {
  font-family: 'Geist';
  src: url('fonts/Geist.woff2') format('woff2');
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
}

:root {
  /* Colour */
  --paper: #F7F7F4;
  --paper-veil: rgba(247, 247, 244, 0.97);
  --ink: #1A1A19;
  --prose: #262624;
  --prose-soft: #3B3B38;
  --label: #5C5C57;
  --caption: #6E6E69;
  --rule: #DCDCD6;
  --link-underline: #A6A6A0;

  /* Type */
  --serif: 'Newsreader', Georgia, serif;
  --sans: 'Geist', system-ui, sans-serif;

  /* Layout */
  --container: 1320px;
  --gutter: clamp(20px, 5vw, 64px);
  --touch: 44px;
  /* The height a photo may take: the window less the page's own chrome. */
  --fit: calc(100svh - 160px);
  /* A photo page's header, which stays at the top (56 here, 48 on a phone, 44 on its side). */
  --header: 56px;

  /* Motion */
  --bar-slide: 200ms ease-out;
  --photo-fade: 400ms;
}

*, *::before, *::after { box-sizing: border-box; }

html {
  background: var(--paper);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: 0.005em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a { color: inherit; text-decoration: none; }
a:hover { color: var(--label); }
img { display: block; max-width: 100%; }
button {
  font: inherit;
  letter-spacing: inherit;
  color: inherit;
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0;
  margin: 0;
  cursor: pointer;
}
:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.icon { display: block; flex: none; }

.sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.no-js .js-only { display: none !important; }
.on-compact, .on-narrow { display: none; }

.wrap {
  max-width: calc(var(--container) + 2 * var(--gutter));
  margin: 0 auto;
  padding: 0 var(--gutter);
}

/* ---------------------------------------------------------------- Photos */

/* Every photo sits in a box of its own shape, so nothing moves while it loads, and is
   never wider than its column nor taller than the window allows. Never cropped. */
.frame {
  display: block;
  aspect-ratio: var(--ar);
  width: min(100%, calc(var(--fit) * var(--ar)));
  background: transparent;
}
.frame picture, .frame img {
  display: block;
  width: 100%;
  height: 100%;
}
.js .frame img { opacity: 0; transition: opacity var(--photo-fade) ease-out; }
.js .frame img.is-seen { opacity: 1; }

/* ---------------------------------------------------------------- Text */

.caption { margin: 0; font-size: 14px; color: var(--caption); }
/* "· 3 photographs" never breaks across lines, so "photographs" is never left alone. */
.count { white-space: nowrap; }
.num { font-size: 13px; color: var(--caption); font-variant-numeric: tabular-nums; }
.meta { margin: 0; font-size: 13px; line-height: 1.8; color: var(--label); }
.headline { font-family: var(--serif); font-weight: 400; font-style: normal; }
/* Italic is used for one thing only: a photograph's name. */
.headline.is-name { font-style: italic; }

.page-title {
  margin: 0;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(44px, 5vw, 64px);
  line-height: 1.02;
  letter-spacing: -0.02em;
}

.prose {
  font-family: var(--serif);
  font-size: 20px;
  line-height: 1.65;
  color: var(--prose);
  /* Old-style figures where the serif has them (Newsreader 1.003 has none: its only
     figures are lining, tabular by default) and proportional ones, which it has and which
     sit better in a line of words than tabular ones. */
  font-variant-numeric: oldstyle-nums proportional-nums;
  font-optical-sizing: auto;
}
.prose > :first-child { margin-top: 0; }
.prose p { margin: 0 0 1.1em; }
.prose > :last-child { margin-bottom: 0; }
.prose a { border-bottom: 1px solid var(--link-underline); }
.prose a:hover { color: var(--label); }
.prose strong { font-weight: 600; }
.prose h2, .prose h3, .prose h4, .prose h5, .prose h6 {
  margin: 1.6em 0 0.5em;
  font-weight: 500;
  line-height: 1.25;
}
.prose h2 { font-size: 1.3em; }
.prose h3 { font-size: 1.12em; }
.prose h4, .prose h5, .prose h6 { font-size: 1em; }
.prose ul, .prose ol { margin: 0 0 1.1em; padding-left: 1.3em; }
.prose li { margin: 0 0 0.3em; }
.prose blockquote {
  margin: 0 0 1.1em;
  padding-left: 1.1em;
  border-left: 1px solid var(--rule);
  color: var(--prose-soft);
}
/* An unfilled row's example address: its words in brackets, not a link. */
.placeholder { color: var(--caption); }
.prose code { font-family: ui-monospace, Menlo, monospace; font-size: 0.85em; }
.prose pre { margin: 0 0 1.1em; white-space: pre-wrap; }
.prose hr { margin: 2em 0; border: 0; border-top: 1px solid var(--rule); }

/* ---------------------------------------------------------------- Site header and footer */

.site-header {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px 40px;
  padding-top: 36px;
}
.site-name {
  font-family: var(--serif);
  font-size: 22px;
  letter-spacing: 0.005em;
}
.site-nav { display: flex; gap: 32px; font-size: 13px; font-weight: 450; }
.site-nav a {
  display: inline-block;
  /* 44 points to touch, without moving the words. */
  padding: 12px 4px;
  margin: 0 -4px;
  color: var(--label);
  border-bottom: 1px solid transparent;
}
.site-nav a.is-current { color: var(--ink); }
.site-nav a.is-section { border-bottom-color: var(--ink); }
.site-header .back { padding: 14px 0; font-size: 13px; }

.site-footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 16px 40px;
  padding: 28px 0 56px;
  font-size: 14px;
  color: var(--caption);
}
.site-footer a { color: inherit; display: inline-block; padding: 12px 0; margin: -12px 0; }
.site-footer a:hover { color: var(--ink); }
/* With the copyright line switched off, the way on keeps its place at the right. */
.site-footer > a:first-child { margin-left: auto; }
.site-footer.is-ruled {
  margin-top: clamp(96px, 12vw, 180px);
  border-top: 1px solid var(--rule);
  font-size: 13px;
  color: var(--label);
}

/* ---------------------------------------------------------------- Galleries index */

.covers {
  list-style: none;
  margin: 0;
  padding: clamp(64px, 9vw, 128px) 0 clamp(96px, 12vw, 160px);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 480px), 1fr));
  gap: clamp(72px, 9vw, 120px) clamp(32px, 4vw, 64px);
  align-items: start;
}
.cover a { display: flex; flex-direction: column; gap: 22px; }
.cover a:hover { color: var(--ink); }
.cover-text { display: flex; flex-direction: column; gap: 6px; }
.cover-title {
  margin: 0;
  font-family: var(--serif);
  font-weight: 400;
  font-size: 34px;
  line-height: 1.1;
  letter-spacing: -0.01em;
}

/* ---------------------------------------------------------------- Gallery */

.gallery-head {
  padding-top: clamp(64px, 9vw, 120px);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-end;
  gap: 24px 64px;
}
.gallery-head .titles { display: flex; flex-direction: column; gap: 10px; flex: 1 1 420px; }
.intro {
  margin-top: 18px;
  max-width: 52ch;
  font-size: 20px;
  line-height: 1.55;
  color: var(--prose-soft);
}
.intro p { margin: 0 0 0.6em; }

/* The Index, the gallery's one view: justified rows across the page's width, each photo as
   wide as its shape asks, nothing cropped, its number and headline under it. Rows are
   about 220 pixels high (300 from 1200 across); on a phone upright that is one landscape
   photo to a row, or two upright ones. These flex rows are the fallback without the
   script, their last row unstretched (the ::after). */
.tiles {
  --row: 220px;
  list-style: none;
  margin: 0;
  padding: clamp(72px, 9vw, 120px) 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 48px 16px;
}
.tiles::after { content: ""; flex: 1000000 1 0; }
.tile { flex: var(--ar) 1 calc(var(--ar) * var(--row)); min-width: 0; }
@media (min-width: 1200px) {
  .tiles { --row: 300px; }
}
/* With the script, site.js sets each tile's width so every row, the last one too where it
   can, runs the page's full width. */
.tiles.is-justified::after { display: none; }
.tile .frame { width: 100%; }
.tile a { display: block; }
.tile-label { display: flex; gap: 10px; align-items: baseline; margin-top: 12px; }
.tile .headline { font-size: 18px; line-height: 1.2; }

.gallery-end {
  margin-top: clamp(120px, 14vw, 220px);
  border-top: 1px solid var(--rule);
  padding: 40px 0 24px;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-end;
  gap: 24px;
}
.gallery-end .all { padding: 12px 0; font-size: 13px; color: var(--label); }
.gallery-end .all:hover { color: var(--ink); }
.next-gallery {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
  margin-left: auto;
  text-align: right;
}
.next-gallery .kicker { font-size: 14px; color: var(--caption); }
.next-gallery .title {
  font-family: var(--serif);
  font-size: 34px;
  line-height: 1.1;
  letter-spacing: -0.01em;
}

/* ---------------------------------------------------------------- Stories

   A story is an article with its photos placed in it, magazine style (Ryan, 8 November
   2026). The words keep a measure of 680 pixels, centred; a photo is as wide as the
   measure, or (wide) up to 1180, never cropped and never taller than the window allows;
   the wall's 64 to 96 pixels of paper stand between words and photos. */

/* The stories, on the home page and their own list: led by their words, not a grid of
   covers, so a story never looks like a gallery. The first is wide: from 1001 pixels its
   cover takes about 60% of the page at the left, its title, standfirst and date at the
   right (stacked on a phone). The rest are rows, a picture of about a third of the page
   and the words beside it. Each entry is one link. */
.story-list {
  list-style: none;
  margin: 0;
  padding: clamp(64px, 9vw, 128px) 0 0;
  display: flex;
  flex-direction: column;
  gap: clamp(64px, 7vw, 104px);
}
.story-entry a { display: grid; gap: 22px; align-items: start; }
.story-entry a:hover { color: var(--ink); }
.story-entry .frame { margin: 0; }
.entry-text { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.entry-title {
  margin: 0;
  font-family: var(--serif);
  font-weight: 400;
  font-size: 30px;
  line-height: 1.1;
  letter-spacing: -0.01em;
}
.entry-standfirst {
  margin: 0;
  max-width: 52ch;
  font-family: var(--serif);
  font-size: 19px;
  line-height: 1.45;
  color: var(--prose-soft);
}
.entry-text .caption { margin-top: 4px; }
.story-entry.is-lead .entry-title { font-size: clamp(36px, 3.4vw, 48px); line-height: 1.04; letter-spacing: -0.015em; }
.story-entry.is-lead .entry-standfirst { font-size: clamp(20px, 1.6vw, 23px); }
@media (min-width: 701px) {
  .story-entry.is-row a {
    grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
    column-gap: clamp(32px, 4vw, 64px);
  }
  .story-entry.is-row .entry-text { padding-top: 2px; }
}
@media (min-width: 1001px) {
  .story-entry.is-lead a {
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    column-gap: clamp(40px, 4vw, 72px);
  }
  .story-entry.is-lead .entry-text { gap: 14px; padding-top: 2px; }
}

/* Then the galleries' covers, after a hairline and more paper than lies between any two
   stories. No label over either (§9): a heading for screen readers alone. */
.has-stories .index-galleries {
  margin-top: clamp(112px, 13vw, 200px);
  border-top: 1px solid var(--rule);
}
.has-stories .index-galleries .covers { padding-top: clamp(64px, 8vw, 112px); }

.stories-list .page-title { padding-top: clamp(64px, 9vw, 120px); }
.stories-list .story-list { padding: clamp(56px, 7vw, 96px) 0 clamp(96px, 12vw, 160px); }
.page-index .story-list { padding-bottom: 0; }

.story-page {
  --measure: 680px;
  --wide: 1180px;
  --beat: clamp(64px, 7vw, 96px);
  /* A photo and its caption in one screen. */
  --fit: calc(100svh - 150px);
}
.story-head {
  max-width: var(--measure);
  margin: 0 auto;
  padding-top: clamp(64px, 9vw, 120px);
}
.standfirst {
  margin: 22px 0 0;
  font-family: var(--serif);
  font-size: 24px;
  line-height: 1.45;
  letter-spacing: -0.003em;
  color: var(--prose-soft);
}
.story-date { margin-top: 18px; }
.story-body { padding-top: var(--beat); }
.story-text { max-width: var(--measure); margin: 0 auto; }
.story-figure {
  margin: var(--beat) auto;
  width: min(100%, var(--measure), calc(var(--fit) * var(--ar)));
}
.story-figure.is-wide { width: min(100%, var(--wide), calc(var(--fit) * var(--ar))); }
.story-body > .story-figure:first-child { margin-top: 0; }
.story-figure .frame { width: 100%; cursor: zoom-in; }
/* At the measure, the figure is the text's width: a photo narrower than that (an upright
   one) is centred in it, and its caption starts at the text's left edge. */
.story-figure.is-measure { width: min(100%, var(--measure)); }
.story-figure.is-measure .frame { width: min(100%, calc(var(--fit) * var(--ar))); margin: 0 auto; }
/* The label as a photo page's, a size down: the name in italic or the identifier in
   roman, then the rest of the identifier and the date in grey. */
.story-caption { margin-top: 16px; display: flex; flex-direction: column; gap: 4px; }
.story-caption .headline { font-size: 20px; line-height: 1.25; }
.story-caption .meta { font-size: 13px; line-height: 1.5; color: var(--caption); }
/* A photo at the left or right of the words (Ryan, 8 November 2026: "floated left or right
   … and then the text running alongside of it"). It is set in the passage just before the
   words that follow it, which run beside it and on below it; the passage holds it
   (has-float), and a photo on a line of its own, the end's links and the body's end clear
   it besides, so nothing rides up beside it or under it. Its caption stays beneath it,
   within its width, in the caption's own type rather than the words'. Below 701 pixels
   across there is no room for words beside a photo: it stands on a line of its own at the
   measure, as [photo 3] does. */
.story-text.has-float { display: flow-root; }
.story-figure:not(.float), .story-end { clear: both; }
.story-body::after { content: ""; display: block; clear: both; }
.story-figure.float {
  width: min(100%, var(--measure));
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  font-variant-numeric: normal;
}
/* Its link is a photo, not words: no underline. */
.story-figure.float .frame { width: min(100%, calc(var(--fit) * var(--ar))); margin: 0 auto; border-bottom: 0; }
@media (max-width: 700px) {
  /* Stacked, a photo that starts a passage after another passage has the paper above it
     that a photo between passages has. */
  .story-text + .story-text > .story-figure.float:first-child { margin-top: var(--beat); }
}
@media (min-width: 701px) {
  /* 42% of the 680 measure, about 286 across: room for about 45 characters beside it.
     Its top sits a little below the line's top, level with the letters of the first line
     beside it. Never taller than the window allows; never cropped. */
  .story-figure.float {
    clear: both;
    width: min(42%, calc(var(--fit) * var(--ar)));
    margin: 0.35em 0 24px 32px;
  }
  .story-figure.float.left { float: left; margin: 0.35em 32px 24px 0; }
  .story-figure.float.right { float: right; }
  .story-figure.float .frame { width: 100%; }
  .story-figure.float .story-caption { margin-top: 10px; gap: 2px; }
  .story-figure.float .story-caption .headline { font-size: 15px; line-height: 1.3; }
  .story-figure.float .story-caption .meta { font-size: 12px; line-height: 1.45; }
}
@media (min-width: 701px) and (max-width: 1000px) {
  /* On a tablet an upright photo at 42% would stand beside a long column of a few words a
     line; a little narrower, it leaves the words more room. */
  .story-figure.float.is-portrait { width: min(36%, calc(var(--fit) * var(--ar))); }
}

/* The end's links stand at the edges of the story's wide photos (the widest a wide photo
   is drawn here), or the measure's where there is none. */
.story-end { width: min(100%, var(--measure)); margin-left: auto; margin-right: auto; }
.story-page.has-wide .story-end { width: min(100%, var(--wide), calc(var(--fit) * var(--wide-ar, 1.5))); }
/* The last story hands over to the galleries. */
.story-onward { margin-left: auto; padding: 12px 0; font-size: 13px; color: var(--label); }
.story-onward:hover { color: var(--ink); }

/* ---------------------------------------------------------------- Compact bar (§7) */

.compact-bar {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 20;
  height: 56px;
  background: var(--paper-veil);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--rule);
  transform: translateY(-100%);
  visibility: hidden;
  transition: transform var(--bar-slide), visibility 0s linear 200ms;
}
.compact-bar.is-shown {
  transform: none;
  visibility: visible;
  transition: transform var(--bar-slide), visibility 0s;
}
.bar-inner {
  max-width: calc(var(--container) + 2 * var(--gutter));
  height: 100%;
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 12px;
  font-size: 13px;
}
.bar-back {
  justify-self: start;
  display: flex;
  align-items: center;
  min-height: var(--touch);
  min-width: var(--touch);
}
.bar-title {
  justify-self: center;
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-family: var(--serif);
  font-size: 21px;
}
.bar-end { justify-self: end; display: flex; align-items: center; gap: 28px; }
.bar-count { color: var(--label); font-variant-numeric: tabular-nums; white-space: nowrap; }
.bar-full {
  justify-self: end;
  width: var(--touch);
  height: var(--touch);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* ---------------------------------------------------------------- Photo detail */

/* The header stays at the top while the page scrolls, as the compact bar's paper: the
   site's name and home at the left, the gallery and the count in the middle, and
   nothing at the right. Ryan asked for it on photo pages, over §7. */
.photo-header {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  z-index: 20;
  height: var(--header);
  background: var(--paper-veil);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--rule);
}
.photo-header .site-name { justify-self: start; display: block; padding: 10px 0; font-size: 20px; white-space: nowrap; }
.photo-header .where {
  justify-self: center;
  min-width: 0;
  max-width: 100%;
  margin: 0;
  display: flex;
  align-items: center;
  white-space: nowrap;
}
/* A long gallery title gives way, ending in an ellipsis; the dot keeps its room either
   side and the count stays whole. */
.photo-header .back { min-width: 0; overflow: hidden; text-overflow: ellipsis; padding: 12px 0; }
.photo-header .sep { flex: none; margin: 0 8px; color: var(--link-underline); }
.photo-header .position { flex: none; color: var(--caption); font-variant-numeric: tabular-nums; }

/* The photo and its Full screen control fit the window together: the header (--header),
   the room above the photo (--above), the control below (52) and a little paper (20). */
.photo-page {
  --above: clamp(28px, 6svh, 72px);
  --fit: calc(100svh - var(--header) - var(--above) - 72px);
  max-width: 1180px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 340px) minmax(0, 640px);
  grid-template-areas:
    "photo photo"
    "label story"
    "pager pager"
    "copyright copyright";
  justify-content: space-between;
  column-gap: 72px;
}
.photo-figure { grid-area: photo; margin: 0; padding-top: var(--above); }
/* A landscape photo leaves room under it for its label, so the headline, the place and
   date and the camera line are all in the first screen (Ryan: details below the fold
   made people scroll); the story continues below. Between 701 and 1000 pixels across
   (a tablet upright, a narrow window); wider, the words stand beside the photo (Desktop,
   below). The page is no wider than the photo (board 03), and two columns in a page
   that narrow would leave the label and the story strips, so the label runs the photo's
   width, its headline on one line, and starts beside the full-screen glyph, at the
   photo's foot; the story follows it.
   --label-room is all that, under the photo: 28 of paper, a headline of one line, the
   place and date (24 + 2 × 21), the camera line (12 + 21) and 16 of paper. */
@media (min-width: 701px) and (max-width: 1000px) and (min-height: 500px) {
  .photo-page.is-landscape {
    --above: clamp(20px, 3svh, 40px);
    --label-room: calc(143px + 1.02 * var(--headline-size));
    --fit: calc(100svh - var(--header) - var(--above) - var(--label-room));
    max-width: min(1180px, calc(var(--fit) * var(--ar)));
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "photo" "label" "story" "pager" "copyright";
  }
  /* Up 24 into the full-screen control's 52, clear of its 44 at the right. */
  .photo-page.is-landscape .photo-label {
    margin-top: -24px;
    padding-top: 0;
    max-width: calc(100% - 72px);
  }
  .photo-page.is-landscape .story { padding-top: 48px; }
}
.photo-wrap {
  position: relative;
  aspect-ratio: var(--ar);
  width: min(100%, calc(var(--fit) * var(--ar)));
  margin: 0 auto;
}
.photo-wrap .frame { width: 100%; height: 100%; cursor: zoom-in; }
.full-corner {
  display: none;
  position: absolute;
  right: 8px;
  bottom: 8px;
  width: var(--touch);
  height: var(--touch);
  align-items: center;
  justify-content: center;
  background: rgba(247, 247, 244, 0.88);
  color: var(--ink);
}
.full-under {
  display: flex;
  justify-content: flex-end;
  margin: 8px auto 0;
  width: min(100%, calc(var(--fit) * var(--ar)));
}
/* The glyph alone, in the caption's grey, its right edge on the photo's; the button
   round it is the 44-pixel target. Its name is the help tag (title). */
.full-under button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--touch);
  height: var(--touch);
  margin-right: calc((18px - var(--touch)) / 2);
  color: var(--caption);
}
.full-under button:hover, .full-under button:focus-visible { color: var(--ink); }

.photo-label { grid-area: label; padding-top: clamp(56px, 7vw, 104px); }
.photo-page { --headline-size: clamp(36px, 3.6vw, 48px); }
.photo-label .headline {
  margin: 0;
  font-size: var(--headline-size);
  font-weight: 350;
  line-height: 1.02;
  letter-spacing: -0.015em;
}
.photo-label .meta { margin-top: 24px; line-height: 1.6; }
.photo-label .meta .place { color: var(--ink); }
.photo-label .meta .date { color: var(--label); }
.photo-label .headline + .meta { margin-top: 24px; }
.photo-label > .meta:first-child { margin-top: 0; }
/* The camera and exposure: an aside, a step quieter than the caption above it. A line too
   long for its column breaks between the equipment and the exposure first, then between
   parts, each part keeping its dot. */
.details {
  margin: 12px 0 0;
  font-size: 13px;
  line-height: 1.6;
  color: var(--caption);
}
.details .group, .details .part { display: inline-block; }
.details .sep { color: var(--link-underline); padding: 0 1px; }
.photo-label > .details:first-child { margin-top: 0; }

.story { grid-area: story; padding-top: clamp(56px, 7vw, 104px); max-width: 640px; }

.pager {
  grid-area: pager;
  margin-top: clamp(96px, 11vw, 160px);
  border-top: 1px solid var(--rule);
  padding: 32px 0 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 32px;
}
.pager a { display: flex; align-items: center; gap: 20px; min-height: var(--touch); }
.pager a:hover { color: var(--ink); }
.pager a:hover .pager-title { color: var(--label); }
.pager .next { margin-left: auto; text-align: right; }
.pager .all .dir { font-size: 13px; }
.pager-text { display: flex; flex-direction: column; gap: 6px; }
.pager .next .pager-text { align-items: flex-end; }
.pager .dir { font-size: 13px; color: var(--label); }
.pager-title { font-family: var(--serif); font-size: 22px; line-height: 1.2; }
/* One box for every thumbnail, 126 × 84, the photo whole inside it on the paper, so the
   titles beside them start in one straight line whatever the photos' shapes. */
.pager .thumb { display: block; width: 126px; height: 84px; flex: none; }
.pager .thumb picture, .pager .thumb img { width: 100%; height: 100%; }
.pager .thumb img { object-fit: contain; }

/* "© 2026 Ryan Victory" under the pager, quiet: the caption's grey, small, one line,
   starting where the pager starts. On a desktop it is the column's foot, its 52 pixels
   matching the full-screen control's under the photo, so the last thumbnail's foot stays
   on the photo's. */
.photo-footer {
  grid-area: copyright;
  padding: 24px 0 72px;
  font-size: 13px;
  line-height: 18px;
  color: var(--caption);
}

/* ================================================================ Desktop: the words beside the photo

   From 1001 pixels across, everything is in the first screen where it can be (Ryan, 8
   November 2026: the photo further left, the words and the way to the next photo to its
   right). The photo is as large as the window's height allows, less the header, the paper
   above it and its full-screen control below, and as wide as the column beside it leaves;
   never larger than its own pixels. The column is 320 to 420 pixels: the label at the
   photo's top, the story under it, and at the column's foot previous above next, the last
   thumbnail's foot on the photo's. Short words leave the page one screen high; a long
   story makes it longer. The photo and the column are one group, centred, up to 1800
   pixels across. */
@media (min-width: 1001px) and (min-height: 500px) {
  .page-photo .wrap,
  .photo-header .bar-inner { max-width: calc(1800px + 2 * var(--gutter)); }
  .photo-page {
    --above: clamp(24px, 4svh, 48px);
    --fit: calc(100svh - var(--header) - var(--above) - 72px);
    /* The photo's width at that height, no more than its own. */
    --photo-w: min(calc(var(--fit) * var(--ar)), var(--w, 100000px));
    max-width: none;
    /* The column takes about 28% of the window, 320 to 420, and the photo the rest up to
       its width; a narrow photo leaves the column its full 420. */
    grid-template-columns:
      fit-content(var(--photo-w))
      clamp(320px, max(28vw, calc(100% - 48px - var(--photo-w))), 420px);
    grid-template-rows: auto 1fr auto auto;
    grid-template-areas:
      "photo label"
      "photo story"
      "photo pager"
      "photo copyright";
    justify-content: center;
    column-gap: 48px;
    padding-bottom: 20px;
  }
  .photo-figure { align-self: start; }
  .photo-wrap,
  .full-under { width: min(100%, var(--photo-w)); margin-left: 0; margin-right: 0; }
  .photo-label { align-self: start; margin: 0; padding-top: var(--above); max-width: none; }
  .story { padding-top: 40px; max-width: none; }
  .pager {
    align-self: end;
    margin-top: 48px;
    padding: 24px 0 0;
    flex-direction: column;
    align-items: stretch;
    gap: 16px;
  }
  .pager .next { margin-left: 0; text-align: left; }
  .pager .next .pager-text { align-items: flex-start; }
  /* Each thumbnail first, in its fixed box, so the two titles start together. */
  .pager .prev, .pager .next { display: grid; grid-template-columns: 126px minmax(0, 1fr); align-items: center; column-gap: 16px; }
  .pager .next .thumb { order: -1; }
  .photo-footer { padding: 24px 0 10px; }
}

/* Below 1500 pixels across a landscape photo has the room: the column keeps to 320 unless
   the photo, held by the window's height, leaves it more. */
@media (min-width: 1001px) and (max-width: 1499px) and (min-height: 500px) {
  .photo-page.is-landscape {
    grid-template-columns:
      fit-content(var(--photo-w))
      clamp(320px, calc(100% - 48px - var(--photo-w)), 420px);
  }
}

/* ---------------------------------------------------------------- About */

.about-title { padding: clamp(64px, 9vw, 120px) 0 clamp(40px, 5vw, 64px); }
.about-body {
  display: flex;
  flex-wrap: wrap;
  gap: 56px clamp(48px, 7vw, 120px);
  align-items: flex-start;
}
.about-figure {
  --fit: calc(100svh - 120px);
  margin: 0;
  flex: 1 1 300px;
  max-width: 460px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.about-figure figcaption { font-size: 13px; line-height: 1.8; color: var(--label); }
.about-figure figcaption .headline { font-size: 17px; color: var(--ink); }
.about-figure figcaption a {
  display: inline-block;
  padding: 12px 0;
  margin: -12px 0;
  text-decoration: underline 1px var(--link-underline);
  text-underline-offset: 4px;
}
.about-text { flex: 999 1 420px; max-width: 660px; display: flex; flex-direction: column; gap: 64px; }
.about-prose .lead {
  margin: 0 0 0.9em;
  font-size: clamp(26px, 2.4vw, 32px);
  line-height: 1.35;
  letter-spacing: -0.008em;
  color: var(--ink);
}
.facts { margin: 0; border-top: 1px solid var(--rule); }
.fact {
  display: grid;
  grid-template-columns: minmax(120px, 160px) minmax(0, 1fr);
  border-bottom: 1px solid var(--rule);
}
.fact dt { padding: 22px 0; font-size: 13px; color: var(--caption); }
.fact dd {
  margin: 0;
  padding: 18px 0;
  font-family: var(--serif);
  font-size: 20px;
  line-height: 1.55;
}
.fact dd p { margin: 0; }
.fact-cameras dd p + p { color: var(--label); }
.fact-contact dd { display: flex; flex-direction: column; gap: 4px; align-items: flex-start; }
.fact a { border-bottom: 1px solid var(--link-underline); }

/* ---------------------------------------------------------------- Not found */

.missing { padding: clamp(64px, 9vw, 120px) 0 160px; display: flex; flex-direction: column; gap: 24px; }
.missing a { display: inline-block; padding: 12px 0; margin: -12px 0; }

/* ================================================================ Tablet upright: the photo page stacks

   Below about 1000 pixels across, two columns would leave the story a narrow strip, so
   the photo, its label, the story and the pager stand one under the other. */

@media (min-width: 701px) and (max-width: 1000px) and (min-height: 500px) {
  .photo-page {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "photo" "label" "story" "pager" "copyright";
  }
  .photo-label { padding-top: 56px; }
  .story { padding-top: 32px; }
}

/* ================================================================ Narrow: a phone upright */

@media (max-width: 700px) and (min-height: 500px), (max-width: 480px) {
  :root { --gutter: 20px; --fit: calc(100svh - 120px); --header: 48px; }
  .on-wide { display: none !important; }
  .on-compact, .on-narrow { display: inline; }

  .site-header { align-items: center; padding-top: 14px; }
  .site-name { font-size: 20px; padding: 10px 0; }
  .site-nav { gap: 22px; }
  .site-nav a { padding: 14px 4px; }
  .site-header.has-back .site-nav { display: none; }
  .site-header.has-back .site-name { font-size: 18px; }
  .site-header.has-back { flex-wrap: nowrap; }

  .site-footer { font-size: 13px; padding: 24px 0 48px; }
  .site-footer.is-ruled { margin-top: 80px; }

  .covers { padding: 48px 0 80px; gap: 80px; }
  .cover .frame {
    width: calc(100% + 2 * var(--gutter));
    max-width: none;
    margin: 0 calc(-1 * var(--gutter));
  }
  .cover a { gap: 20px; }
  .cover-title { font-size: 28px; }

  .gallery-head { padding-top: 48px; }
  .gallery-head .titles { gap: 6px; flex-basis: auto; }
  .page-title { font-size: 40px; line-height: 1.05; letter-spacing: -0.015em; }
  .gallery-head .caption { line-height: 1.45; }
  .intro { margin-top: 14px; font-size: 18px; }
  .tiles { padding-top: 56px; gap: 40px 16px; }

  .gallery-end { margin-top: 112px; padding: 28px 0 16px; }
  .gallery-end.has-next .all { display: none; }

  .stories-list .page-title { padding-top: 48px; }
  .stories-list .covers { padding-top: 48px; }
  .story-page { --beat: 56px; --fit: calc(100svh - 110px); }
  .story-list { padding: 48px 0 0; gap: 56px; }
  .stories-list .story-list { padding: 48px 0 80px; }
  .story-entry.is-lead .frame {
    width: calc(100% + 2 * var(--gutter));
    max-width: none;
    margin: 0 calc(-1 * var(--gutter));
  }
  .story-entry.is-lead a { gap: 20px; }
  .story-entry.is-lead .entry-title { font-size: 34px; }
  .story-entry.is-lead .entry-standfirst { font-size: 19px; }
  .story-entry.is-row a { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); column-gap: 16px; }
  .story-entry.is-row .entry-text { gap: 6px; }
  .story-entry.is-row .entry-title { font-size: 22px; }
  .story-entry.is-row .entry-standfirst { font-size: 16px; line-height: 1.4; }
  .story-entry.is-row .caption { font-size: 13px; }
  .has-stories .index-galleries { margin-top: 96px; }
  .has-stories .index-galleries .covers { padding-top: 48px; }
  .story-head { padding-top: 48px; }
  .standfirst { margin-top: 16px; font-size: 21px; line-height: 1.45; }
  .story-date { margin-top: 14px; }
  .story-text { font-size: 19px; line-height: 1.62; }
  /* A wide landscape photo runs edge to edge, its caption kept to the text's edge. */
  .story-figure.is-wide.is-landscape {
    width: calc(100% + 2 * var(--gutter));
    max-width: none;
    margin-left: calc(-1 * var(--gutter));
    margin-right: calc(-1 * var(--gutter));
  }
  .story-figure.is-wide.is-landscape .story-caption { padding: 0 var(--gutter); }
  .story-caption { margin-top: 12px; }
  .story-caption .headline { font-size: 19px; }
  .next-gallery { align-items: flex-start; margin-left: 0; text-align: left; gap: 10px; }
  .next-gallery .title { font-size: 28px; }

  .compact-bar { height: 48px; }
  .bar-inner { padding: 0 8px 0 4px; }
  .bar-back { justify-content: center; }
  .bar-title { font-size: 19px; }
  .bar-count { width: 60px; text-align: right; }

  /* The name at the left, "← Streets · 1 of 3" at the right; full screen is over the photo. */
  .photo-header .bar-inner { grid-template-columns: auto minmax(0, 1fr); gap: 16px; padding: 0 var(--gutter); }
  .photo-header .site-name { font-size: 18px; }
  .photo-header .where { justify-self: end; }
  .photo-header .back { padding: 14px 0; }
  .photo-page {
    --fit: calc(100svh - var(--header) - 92px);
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "photo" "label" "story" "pager" "copyright";
  }
  .photo-figure { padding-top: 28px; }
  .photo-page.is-landscape .photo-wrap {
    width: calc(100% + 2 * var(--gutter));
    margin: 0 calc(-1 * var(--gutter));
  }
  .photo-page.is-portrait .photo-wrap { width: min(calc(100% - 16px), calc(var(--fit) * var(--ar))); }
  .full-under { display: none !important; }
  .js .full-corner { display: flex; }
  .photo-label { padding-top: 40px; }
  .photo-label .headline { font-size: 38px; line-height: 1.04; }
  .photo-label .headline + .meta { margin-top: 18px; }
  .story {
    padding-top: 28px;
    margin-top: 32px;
    border-top: 1px solid var(--rule);
    font-size: 19px;
    line-height: 1.62;
  }
  .pager {
    margin-top: 72px;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: stretch;
    gap: 0;
  }
  .pager a { flex-direction: column; align-items: flex-start; gap: 8px; padding: 22px 16px 22px 0; }
  .pager .prev { border-right: 1px solid var(--rule); }
  .pager .next { grid-column: 2; align-items: flex-end; padding: 22px 0 22px 16px; margin-left: 0; }
  .pager .pager-title { font-size: 18px; }
  .photo-footer { padding: 8px 0 40px; }

  .about-title { padding: 48px 0 32px; }
  .about-body { flex-direction: column; flex-wrap: nowrap; gap: 0; align-items: stretch; }
  .about-figure { flex: none; max-width: none; padding: 0 8px; gap: 14px; }
  .about-figure .frame { margin: 0 auto; }
  .about-text { flex: none; max-width: none; gap: 40px; margin-top: 48px; }
  .about-body.no-photo .about-text { margin-top: 0; }
  .about-prose { border-top: 1px solid var(--rule); padding-top: 28px; font-size: 19px; line-height: 1.62; }
  .about-prose .lead { font-size: 25px; }
  .fact { display: flex; flex-direction: column; gap: 8px; padding: 18px 0; }
  .fact dt, .fact dd { padding: 0; }
  .fact dd { font-size: 18px; line-height: 1.5; }
  .fact-contact dd { gap: 2px; }
  .fact-contact dd a { border-bottom: 0; padding: 10px 0; display: inline-block; }
}

/* ================================================================ Short: a phone on its side */

@media (max-height: 499px) and (min-width: 481px) and (orientation: landscape) {
  :root { --gutter: 44px; --fit: calc(100svh - 48px); --header: 44px; }
  .on-wide { display: none !important; }
  .on-compact { display: inline; }

  .site-header { height: 44px; padding-top: 0; align-items: center; flex-wrap: nowrap; font-size: 13px; }
  .site-name { font-size: 17px; letter-spacing: 0; }
  .site-nav a { padding: 12px 0; }
  .site-header.has-back .site-nav { display: none; }

  .covers { padding: 40px 0 72px; gap: 64px 32px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); }

  .gallery-head { padding: 40px 0 0; flex-wrap: nowrap; gap: 40px; }
  .gallery-head .titles { gap: 14px; flex: 1 1 auto; }
  .page-title { font-size: 48px; line-height: 1.05; letter-spacing: -0.015em; }
  .intro { max-width: 300px; font-size: 17px; line-height: 1.5; margin-top: 0; }
  .gallery-head .titles .intro { margin-top: 4px; }
  .tiles { padding-top: 40px; }

  .gallery-end { margin-top: 110px; padding: 28px 0 16px; }
  .next-gallery .title { font-size: 28px; }

  .story-list { padding-top: 40px; gap: 56px; }
  .has-stories .index-galleries { margin-top: 96px; }
  .has-stories .index-galleries .covers { padding-top: 48px; }
  .story-page { --beat: 56px; --fit: calc(100svh - 40px); }
  .story-head { padding-top: 40px; }
  .standfirst { font-size: 20px; }
  .story-text { font-size: 18px; line-height: 1.62; }

  .compact-bar { height: 44px; }
  .bar-title { font-size: 18px; }

  /* One 44-pixel line (board 12); full screen is over the photo's corner, as upright. */
  .photo-header .site-name { font-size: 17px; padding: 8px 0; }
  .photo-page {
    --fit: calc(100svh - var(--header) - 16px);
    max-width: none;
    grid-template-columns: 240px minmax(0, 1fr);
    column-gap: 48px;
  }
  .photo-figure { padding-top: 0; }
  .full-under { display: none !important; }
  .js .full-corner { display: flex; }
  .photo-label { padding-top: 64px; }
  .photo-label .headline { font-size: 34px; line-height: 1.04; }
  .photo-label .headline + .meta { margin-top: 12px; }
  .story { padding-top: 64px; font-size: 18px; line-height: 1.62; max-width: none; }
  .photo-page.is-portrait {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas:
      "photo label"
      "story story"
      "pager pager"
      "copyright copyright";
  }
  .photo-page.is-portrait .photo-wrap { width: calc(var(--fit) * var(--ar)); max-width: 100%; margin: 0 0 0 auto; }
  .photo-page.is-portrait .photo-label { align-self: end; padding-top: 0; max-width: 300px; }
  .pager { margin-top: 72px; padding: 22px 0 0; }
  .pager a { flex-direction: column; align-items: flex-start; gap: 6px; }
  .pager .next { align-items: flex-end; }
  .pager .pager-title { font-size: 18px; }
  .photo-footer { padding: 16px 0 40px; }

  /* Side by side, as on a desktop: the photo a column, the words beside it. */
  .about-body { flex-wrap: nowrap; gap: 48px; }
  .about-figure { --fit: calc(100svh - 60px); flex: 0 1 260px; }
  .about-text { flex: 1 1 360px; }
}

/* ================================================================ Full-screen viewer (§8) */

.viewer {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: var(--paper);
  color: var(--ink);
  overflow: hidden;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  font-size: 13px;
}
.viewer[hidden], .viewer [hidden] { display: none !important; }
.viewer:fullscreen { background: var(--paper); }
.viewer:focus { outline: none; }
.viewer::backdrop { background: var(--paper); }
.viewer .v-img {
  position: absolute;
  max-width: none;
  transform-origin: 50% 50%;
  will-change: transform;
  -webkit-user-drag: none;
}
.viewer .v-chrome { transition: opacity 300ms ease-out; }
.viewer.is-idle .v-chrome { opacity: 0; pointer-events: none; }
.viewer.is-idle { cursor: none; }
.viewer button {
  width: var(--touch);
  height: var(--touch);
  display: flex;
  align-items: center;
  justify-content: center;
}
.v-pos {
  position: absolute;
  left: 32px;
  top: 24px;
  height: var(--touch);
  margin: 0;
  display: flex;
  align-items: center;
  color: var(--label);
  font-variant-numeric: tabular-nums;
}
.v-close { position: absolute; right: 24px; top: 24px; }
.v-prev, .v-next { position: absolute; top: calc(50% - 22px); }
.v-prev { left: 24px; }
.v-next { right: 24px; }
.viewer button[disabled] { visibility: hidden; }
.v-caption {
  position: absolute;
  left: 160px;
  right: 160px;
  bottom: 22px;
  margin: 0;
  display: flex;
  justify-content: center;
  align-items: baseline;
  gap: 18px;
  text-align: center;
}
.v-caption .headline { font-size: 18px; }
.v-caption .v-meta { color: var(--label); }
.v-keys { position: absolute; right: 32px; bottom: 22px; margin: 0; color: var(--label); }
.v-zoom {
  position: absolute;
  left: 12px;
  bottom: 20px;
  height: 36px;
  padding: 0 14px;
  display: flex;
  align-items: center;
  gap: 12px;
  background: rgba(247, 247, 244, 0.9);
}
.v-zoom .v-level { font-variant-numeric: tabular-nums; }
.v-zoom .v-hint { color: var(--label); }
.v-map {
  position: absolute;
  right: 12px;
  bottom: 20px;
  padding: 4px;
  background: rgba(247, 247, 244, 0.9);
}
.v-map-frame { position: relative; border: 1px solid var(--label); }
.v-map-view { position: absolute; border: 1px solid var(--ink); }
.viewer.is-zoomed .v-caption,
.viewer.is-zoomed .v-prev,
.viewer.is-zoomed .v-next,
.viewer.is-zoomed .v-pos,
.viewer.is-zoomed .v-keys { display: none; }
.viewer.is-zoomed .v-close { background: rgba(247, 247, 244, 0.9); }
.viewer .v-gallery { white-space: pre; }

/* A tablet's mat is 48 pixels (site.js), so the chevrons sit inside it, off the photo. */
@media (min-width: 701px) and (max-width: 1100px) and (min-height: 500px) {
  .v-prev { left: 2px; }
  .v-next { right: 2px; }
}

@media (max-width: 700px) and (min-height: 500px), (max-width: 480px) {
  .v-pos { left: 20px; top: 6px; }
  .v-pos .v-gallery { display: none; }
  .v-close { right: 6px; top: 6px; }
  .v-caption {
    left: 20px;
    right: 100px;
    bottom: 28px;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    text-align: left;
  }
  .v-caption .headline { font-size: 19px; line-height: 1.2; }
  .v-caption .v-meta { line-height: 1.5; }
  .v-meta .v-sep { display: none; }
  .v-meta > span { display: block; }
  .v-prev, .v-next { top: auto; bottom: 28px; }
  .v-prev { left: auto; right: 50px; }
  .v-next { right: 6px; }
  .v-keys { display: none; }
}

@media (max-height: 499px) and (min-width: 481px) and (orientation: landscape) {
  .v-pos { left: 20px; top: 8px; }
  .v-pos .v-gallery { display: none; }
  .v-close { right: 8px; top: 8px; }
  .v-prev { left: 8px; }
  .v-next { right: 8px; }
  .v-caption {
    left: 20px;
    right: auto;
    bottom: 20px;
    width: var(--side, 128px);
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    text-align: left;
  }
  .v-caption .headline { font-size: 16px; line-height: 1.2; }
  .v-caption .v-meta { line-height: 1.7; }
  .v-meta .v-sep { display: none; }
  .v-meta > span { display: block; }
  .v-keys { display: none; }
}

/* ================================================================ Touch: no key hints */

@media (hover: none), (pointer: coarse) {
  .v-keys { display: none !important; }
}

/* ================================================================ Reduced motion */

@media (prefers-reduced-motion: reduce) {
  .js .frame img { opacity: 1; transition: none; }
  .compact-bar, .compact-bar.is-shown { transition: none; }
  .viewer .v-chrome { transition: none; }
}
