/* Vermeer Family Reunion Book.
   The site is set like a printed book: a paper ground, hairline rules instead
   of boxes, a display serif for the chapter openers, and small tracked sans
   labels wherever a real book would use metal type — folios, running heads,
   plate numbers. Nothing floats; everything hangs off a rule. */

@font-face {
  font-family: "Crimson Pro";
  src: url("fonts/crimson-pro-variable.woff2") format("woff2");
  font-weight: 200 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Crimson Pro";
  src: url("fonts/crimson-pro-italic-variable.woff2") format("woff2");
  font-weight: 200 900;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "Cormorant Garamond";
  src: url("fonts/cormorant-garamond-variable.woff2") format("woff2");
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Cormorant Garamond";
  src: url("fonts/cormorant-garamond-italic-variable.woff2") format("woff2");
  font-weight: 300 700;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: Karla;
  src: url("fonts/karla-variable.woff2") format("woff2");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Paper */
  --paper: #edeae3;
  --paper-warm: #e6e3da;
  --paper-light: #f5f3ed;
  --tint: #dedace;

  /* Ink. The muted tones are darker than a print sample would be so that
     10px tracked labels still clear 4.5:1 against every paper we use. */
  --ink: #22211d;
  --forest: #2b4034;
  --rust: #8c3b2e;
  --rust-dark: #6f2c22;
  --stone: #575344;
  --stone-light: #645f4e;

  /* Rules, in descending weight */
  --rule: rgb(40 38 30 / 28%);
  --rule-soft: rgb(40 38 30 / 18%);
  --rule-faint: rgb(40 38 30 / 14%);

  --shell: 1320px;
  --gutter: clamp(1rem, 3.4vw, 2.5rem);
  --label-font: Karla, "Helvetica Neue", Arial, sans-serif;
  --display-font: "Cormorant Garamond", Georgia, serif;

  color: var(--ink);
  background: var(--paper);
  font-family: "Crimson Pro", Georgia, serif;
  font-size: 18px;
  line-height: 1.55;
}

* { box-sizing: border-box; }

/* Any display rule of ours outweighs the browser's own [hidden] default, so
   hiding something in markup has to be stated once, loudly, or a panel we mean
   to swap out simply stays on screen. */
[hidden] { display: none !important; }

/* The header is sticky, so anything scrolled to — an anchor, or the upload
   confirmation taking focus — has to stop clear of it or arrive underneath. */
html { scroll-behavior: smooth; scroll-padding-top: 5.5rem; }

body {
  min-width: 20rem;
  min-height: 100vh;
  margin: 0;
  background:
    linear-gradient(rgb(237 234 227 / 90%), rgb(230 227 218 / 96%)),
    url("textures/paper-fibers.svg");
  -webkit-font-smoothing: antialiased;
}

a { color: var(--forest); text-underline-offset: .16em; }
a:hover { color: var(--rust); }
img, video { display: block; max-width: 100%; }

:focus-visible {
  outline: .14rem solid var(--rust);
  outline-offset: .18rem;
}

h1, h2, h3 { font-family: var(--display-font); font-weight: 600; letter-spacing: -.015em; }

/* The one repeated typographic device: a small, tracked, uppercase label.
   Used for folios, running heads, counts, plate numbers and eyebrow lines. */
.label,
.eyebrow,
.wordmark__kicker,
.year-tabs a,
.contribute,
.lead-meta span,
.chapters__head,
.chapter-row__no,
.chapter-row__place,
.chapter-row__meta,
.chapter-meta,
.chapter-rule,
.chapter-nav__dir,
.plate__no,
.site-footer p,
.admin-chrome {
  font-family: var(--label-font);
  font-size: .58rem;
  font-weight: 600;
  letter-spacing: .18em;
  line-height: 1.4;
  text-transform: uppercase;
}

.skip-link {
  position: fixed;
  z-index: 100;
  top: .5rem;
  left: .5rem;
  padding: .55rem .9rem;
  transform: translateY(-220%);
  background: var(--paper-light);
  box-shadow: 0 .2rem .8rem rgb(40 38 30 / 22%);
}

.skip-link:focus { transform: translateY(0); }

/* ---------------------------------------------------------------- header */

.site-header {
  position: sticky;
  z-index: 30;
  top: 0;
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
}

.header-bar {
  display: flex;
  width: min(var(--shell), 100%);
  margin: 0 auto;
  padding: .5rem var(--gutter);
  align-items: baseline;
  flex-wrap: wrap;
  gap: .5rem .9rem;
}

.wordmark {
  display: flex;
  margin-right: auto;
  align-items: baseline;
  gap: .5rem;
  color: var(--ink);
  text-decoration: none;
}

.wordmark__name { font-family: var(--display-font); font-size: 1.72rem; line-height: 1; }
.wordmark__kicker { color: var(--stone-light); }
.wordmark:hover .wordmark__name { color: var(--rust); }

.year-tabs { min-width: 0; overflow-x: auto; scrollbar-width: thin; }

.year-tabs ol {
  display: flex;
  width: max-content;
  margin: 0;
  padding: 0;
  gap: .35rem;
  list-style: none;
}

/* Bare numbers with only the current one underlined read as a caption, not as
   the way through the book — on a phone, where these sit on a row of their own,
   there was nothing to say they could be tapped at all. Each year is a chip
   now, and the one you are on is filled. */
.year-tabs a {
  display: block;
  padding: .35rem .6rem;
  border: 1px solid var(--rule);
  background: var(--paper-light);
  color: var(--stone);
  font-variant-numeric: tabular-nums;
  letter-spacing: .14em;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color .16s ease, background .16s ease, color .16s ease;
}

.year-tabs a:hover,
.year-tabs a:focus-visible { border-color: var(--rust); background: var(--paper-warm); color: var(--rust); }

.year-tabs a[aria-current="page"] {
  border-color: var(--rust);
  background: var(--rust);
  color: var(--paper-light);
}

.contribute {
  color: var(--rust);
  letter-spacing: .16em;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: .3em;
}

.contribute:hover { color: var(--ink); }

.admin-chrome {
  display: flex;
  align-items: baseline;
  gap: .7rem;
  color: var(--stone);
}

.admin-chrome strong { color: var(--rust); font-weight: 700; }
.admin-chrome a { color: var(--stone); text-decoration-color: var(--rule); }

.signout button,
.link-button {
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--stone);
  font-family: var(--label-font);
  font-size: .58rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  text-decoration: underline;
  text-underline-offset: .3em;
  cursor: pointer;
}

.signout button:hover,
.link-button:hover { color: var(--rust); }

/* ------------------------------------------------------------------ page */

.page {
  width: min(var(--shell), 100%);
  margin: 0 auto;
  padding: 0 var(--gutter) clamp(1.4rem, 3vw, 2.4rem);
}

/* The opener rises as the page settles. The animation deliberately stays off
   .page, which is an ancestor of the photo viewer: an opacity animation there
   would make .page a stacking context (dropping the viewer behind the sticky
   header) and a transform animation would make it a containing block (pinning
   the viewer inside the article instead of over the viewport). */
.motion-ok .masthead,
.motion-ok .chapter-head { animation: rise-in .6s ease both; }

@keyframes rise-in {
  from { opacity: 0; transform: translateY(1rem); }
  to { opacity: 1; transform: none; }
}

.action-confirmation {
  width: min(var(--shell), 100%);
  margin: .9rem auto 0;
  padding: .55rem var(--gutter);
  border-left: 3px solid var(--rust);
  background: var(--paper-light);
  font-size: .95rem;
}

.action-confirmation[hidden] { display: none; }
.action-confirmation.is-error { border-left-color: var(--rust-dark); background: #f4e6e2; }

/* --------------------------------------------------------------- home */

/* The cover runs at the photograph's own proportions. It used to be a fixed
   16:7 band with object-fit: cover, which cropped a 3:2 group portrait hard
   top and bottom and cut people off at the legs. A cover photograph has to
   show everyone in it. */
/* The book opens as a banner across the top, then a split: the cover
   photograph on one side, the years to choose from on the other. */
.banner { padding-top: clamp(.6rem, 2vw, 1.2rem); }

.home-split {
  display: grid;
  margin-top: clamp(1rem, 2.5vw, 1.6rem);
  align-items: start;
  gap: clamp(1.2rem, 3.5vw, 2.6rem);
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

.lead-photo { margin: 0; }
.lead-photo img { display: block; width: 100%; height: auto; max-height: 34rem; object-fit: cover; }

.lead-photo--empty {
  display: grid;
  aspect-ratio: 4 / 3;
  place-items: center;
  border: 1px solid var(--rule-soft);
  background: var(--tint);
  color: var(--stone-light);
}

.lead-meta {
  display: flex;
  padding: .55rem 0 0;
  border-top: 1px solid var(--rule-soft);
  margin-top: clamp(.8rem, 2vw, 1.2rem);
  align-items: baseline;
  flex-wrap: wrap;
  gap: .35rem 1rem;
  color: var(--stone-light);
}

.lead-meta span + span { margin-left: auto; text-align: right; }

.masthead {
  display: grid;
  padding: 0 0 clamp(.6rem, 1.6vw, 1rem);
  align-items: end;
  gap: clamp(1rem, 3vw, 2.5rem);
  grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
}

.masthead h1 {
  max-width: 15ch;
  margin: 0;
  color: var(--forest);
  font-size: clamp(2.4rem, 5.4vw, 4.2rem);
  line-height: .88;
  letter-spacing: -.02em;
  text-wrap: balance;
}

.masthead__aside { display: flex; flex-direction: column; gap: .75rem; min-width: 0; }
.masthead__intro { max-width: 48ch; margin: 0; font-size: 1.06rem; line-height: 1.5; text-wrap: pretty; }

.masthead__note {
  max-width: 44ch;
  text-wrap: pretty;
  margin: 0;
  padding-top: .65rem;
  border-top: 1px solid var(--rule-faint);
  color: var(--stone);
  font-family: var(--display-font);
  font-size: 1.18rem;
  font-style: italic;
  line-height: 1.35;
}

.chapters { padding-top: 0; }
.chapters__head { margin: 0 0 .6rem; color: var(--stone-light); }
/* The index used to be hairline-separated rows on the page's own paper, which
   on a phone left a year and a title floating with nothing to say they lead
   anywhere — the "Open" was hidden at that width. Every row is now a bordered
   plate of its own with an underlined year and a rust arrow that never leaves,
   so the whole thing reads as navigation rather than a table of contents. */
.chapters__list { display: grid; gap: .45rem; margin: 0; padding: 0; list-style: none; }

.chapter-row {
  display: grid;
  padding: .5rem .7rem;
  align-items: center;
  gap: clamp(.5rem, 1.4vw, 1.1rem);
  grid-template-columns: 1.6rem 3.4rem minmax(0, 1fr) auto auto;
  border: 1px solid var(--rule);
  background: var(--paper-light);
  color: inherit;
  text-decoration: none;
  transition: border-color .16s ease, background .16s ease;
}

.chapter-row:hover,
.chapter-row:focus-visible { border-color: var(--rust); background: var(--paper-warm); color: inherit; }
.chapter-row:hover .chapter-row__arrow { transform: translateX(.2rem); }
.chapter-row__no { color: var(--stone-light); letter-spacing: .1em; }

.chapter-row__plate {
  display: block;
  width: 3.4rem;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--tint);
}

.chapter-row__plate img { width: 100%; height: 100%; object-fit: cover; }

.chapter-row__title {
  display: flex;
  min-width: 0;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .2rem .7rem;
}

.chapter-row__year {
  color: var(--forest);
  font-family: var(--display-font);
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1;
  font-variant-numeric: lining-nums tabular-nums;
  text-decoration: underline;
  text-decoration-color: var(--rule);
  text-decoration-thickness: 1px;
  text-underline-offset: .16em;
}

.chapter-row:hover .chapter-row__year { text-decoration-color: var(--rust); }

.chapter-row__name { font-family: var(--display-font); font-size: 1.2rem; font-style: italic; line-height: 1.05; }
.chapter-row__place { color: var(--stone-light); letter-spacing: .14em; }

.chapter-row__meta {
  display: flex;
  align-items: baseline;
  gap: .8rem;
  color: var(--stone-light);
  letter-spacing: .12em;
  white-space: nowrap;
}

.chapter-row__go {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  color: var(--rust);
  font-family: var(--label-font);
  font-size: .58rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  white-space: nowrap;
}

.chapter-row__arrow { display: inline-block; font-size: 1.2em; transition: transform .16s ease; }

/* ------------------------------------------------------- chapter (year) */

.chapter { padding-top: clamp(.9rem, 2.2vw, 1.5rem); }

.chapter-head { display: flex; margin-bottom: .7rem; align-items: baseline; flex-wrap: wrap; gap: .2rem .8rem; }

/* The chapter opens on a photograph with the story beside it — smaller than
   the book's own cover, and sharing the width rather than taking it. */
.chapter-opener {
  display: grid;
  margin-top: clamp(.6rem, 1.6vw, 1rem);
  align-items: start;
  gap: clamp(1rem, 3vw, 2.2rem);
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

.chapter-opener--plain { grid-template-columns: minmax(0, 1fr); }

/* Capped by height rather than cropped to a fixed shape: a portrait cover
   should sit smaller beside the story, not tower over it, and cropping a
   group photograph to fit is how people lose their heads. */
.chapter-hero { display: flex; margin: 0; justify-content: center; }
/* Sized to fill its half of the page. The cap is high enough that a landscape
   photograph — which most covers are — reaches the full column width, and low
   enough that a portrait one is held back rather than towering over the story.
   Never a fixed shape: cropping a group photograph is how people lose heads. */
.chapter-hero img { width: auto; max-width: 100%; max-height: 32rem; background: var(--tint); }

.chapter-head h1 {
  display: flex;
  margin: 0;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .2rem .8rem;
  font-size: 1rem;
  font-weight: 400;
}

.chapter-year {
  color: var(--forest);
  font-size: clamp(2.2rem, 4vw, 3.2rem);
  font-weight: 600;
  line-height: .9;
  letter-spacing: -.02em;
  font-variant-numeric: lining-nums;
}

.chapter-name { font-size: clamp(1.25rem, 2.4vw, 1.75rem); font-style: italic; line-height: 1; }
.chapter-no { color: var(--rust); font-family: var(--label-font); font-size: .58rem; font-weight: 700; letter-spacing: .18em; text-transform: uppercase; }

.chapter-aside { display: flex; min-width: 0; flex-direction: column; }

.chapter-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .55rem;
  color: var(--stone);
  letter-spacing: .14em;
}

.chapter-meta address { font-style: normal; }
.chapter-meta .dot { width: 3px; height: 3px; background: var(--stone-light); }
.chapter-story { max-width: 62ch; }
.chapter-story p { margin: 0 0 .55rem; font-size: 1rem; line-height: 1.5; text-wrap: pretty; }
.chapter-story p:last-child { margin-bottom: 0; }

.chapter-rule a { color: var(--rust); text-decoration: underline; text-underline-offset: .3em; }
.chapter-rule a:hover { color: var(--ink); }

.chapter-rule {
  display: flex;
  margin-top: clamp(.9rem, 2vw, 1.3rem);
  padding-top: .5rem;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  border-top: 1px solid var(--rule);
  color: var(--stone-light);
}

/* The invitation to the feed: a button, with the description beside it. It
   began life as a micro-label at the end of the photograph count — the exact
   size and position a reader's eye skips. */
.feed-invite {
  display: grid;
  margin: clamp(.9rem, 2.2vw, 1.4rem) 0 0;
  align-items: center;
  gap: clamp(.9rem, 2.5vw, 1.6rem);
  grid-template-columns: auto minmax(0, 1fr);
  color: inherit;
  text-decoration: none;
}

.feed-invite__button {
  display: inline-flex;
  min-height: 3.2rem;
  padding: .8rem 1.2rem;
  align-items: center;
  gap: .6rem;
  border: 1px solid var(--rust);
  background: var(--rust);
  color: var(--paper-light);
  font-family: var(--label-font);
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  white-space: nowrap;
}

.feed-invite:hover .feed-invite__button { background: var(--rust-dark); border-color: var(--rust-dark); }
.feed-invite__arrow { font-size: 1.15em; line-height: 1; }
.motion-ok .feed-invite__arrow { animation: feed-nudge 2.6s ease-in-out infinite; }

.feed-invite__text { display: flex; min-width: 0; flex-direction: column; gap: .1rem; }
.feed-invite__lead { color: var(--forest); font-family: var(--display-font); font-size: clamp(1.15rem, 2.4vw, 1.45rem); font-weight: 600; line-height: 1.15; }
.feed-invite__note { max-width: 62ch; color: var(--stone); font-size: .92rem; line-height: 1.4; text-wrap: pretty; }
.feed-invite__note strong { color: var(--ink); }

@keyframes feed-nudge {
  0%, 70%, 100% { transform: translateY(0); }
  80% { transform: translateY(.22rem); }
  90% { transform: translateY(.08rem); }
}

/* Photographs and the feed share the chapter: three columns of small plates
   beside a column of notes.
   The feed is deliberately NOT sticky and has no height cap. A scroller inside
   a scroller is the one thing worse than a long page — the notes simply run
   down their column for as long as they need, and one page scroll reads
   everything. */
.chapter-body {
  display: grid;
  /* Stretch, so the rule between the two columns runs the length of the
     photographs instead of stopping short where the notes run out. */
  align-items: stretch;
  gap: clamp(1.2rem, 3vw, 2.4rem);
  grid-template-columns: minmax(0, 1fr) minmax(0, 21rem);
}

.chapter-body__plates { min-width: 0; }

.chapter-body__feed {
  min-width: 0;
  padding-left: clamp(1rem, 2.5vw, 1.6rem);
  border-left: 1px solid var(--rule);
}

/* The way in for photographs, at the head of the plates where the first row
   begins. The link in the header is easy to miss once someone is looking at
   pictures, and this is the thing we most want them to do. */
.plates-action { margin: 0 0 clamp(.7rem, 2vw, 1rem); }
.plates-action--end { margin: clamp(.2rem, 1.5vw, .7rem) 0 0; }

.plates-action a {
  display: inline-flex;
  min-height: 2.2rem;
  padding: .4rem .95rem;
  align-items: center;
  gap: .45rem;
  border: 1px solid var(--rust);
  background: var(--rust);
  color: var(--paper-light);
  font-family: var(--label-font);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-decoration: none;
  text-transform: uppercase;
  transition: background .16s ease, border-color .16s ease;
}

.plates-action a:hover,
.plates-action a:focus-visible { background: var(--rust-dark); border-color: var(--rust-dark); }
.plates-action__plus { font-size: 1.15em; font-weight: 400; line-height: 1; }

/* --------------------------------------------------------- contact sheet */

.contact-sheet { margin-top: clamp(.7rem, 1.6vw, 1rem); }

.contact-sheet__grid {
  display: grid;
  margin: 0;
  padding: 0;
  align-items: start;
  gap: 0 .9rem;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  list-style: none;
}

/* Progressive enhancement: site.js measures each plate and hands out row
   spans so the sheet packs like a real contact sheet. Without JS the grid
   above still lays out cleanly, just with even row baselines. */
.contact-sheet__grid.is-masonry { align-items: stretch; grid-auto-rows: 10px; }

.contact-sheet__item { min-width: 0; margin: 0; padding-bottom: 1.4rem; }

.contact-sheet__item > button {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: var(--tint);
  cursor: pointer;
}

.contact-sheet__item > button:hover img { opacity: .88; }

.contact-sheet__item img {
  width: 100%;
  aspect-ratio: var(--ar, 4 / 3);
  object-fit: cover;
  transition: opacity 160ms ease;
}

.contact-sheet__item > button > span {
  display: block;
  padding: .3rem 0 0;
  color: var(--rust);
  font-family: var(--label-font);
  font-size: .58rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.plate-caption {
  display: flex;
  margin: .35rem 0 0;
  align-items: baseline;
  gap: .45rem;
  color: var(--stone);
  font-size: .78rem;
  line-height: 1.25;
}

.plate__no { color: var(--rust); font-weight: 700; letter-spacing: .12em; }
.plate-caption small { display: block; color: var(--stone-light); font-size: .95em; }

/* The chapter turn runs to the page edges, like the foot of a printed page.
   It sits inside the padded page shell, so it reaches back out to the gutter. */
/* ------------------------------------------------------------ guest book */

/* By the door, on the way out: after the photographs, before the chapter turn.
   Notes first and the form last, because what persuades somebody to write is
   reading what everyone else did. */
.guest-book { margin: 0; }
.guest-book h2 { margin: 0 0 .3rem; color: var(--forest); font-family: var(--display-font); font-size: 1.6rem; font-weight: 600; }
.guest-book__lead { max-width: 60ch; margin: 0 0 clamp(.6rem, 1.6vw, .9rem); color: var(--stone); font-size: .92rem; line-height: 1.5; text-wrap: pretty; }
.guest-book__empty { max-width: 60ch; margin: clamp(1rem, 2.5vw, 1.4rem) 0 0; color: var(--stone-light); font-family: var(--display-font); font-size: 1.2rem; font-style: italic; line-height: 1.4; }

.guest-book__notes {
  display: grid;
  width: 100%;
  margin: clamp(1rem, 2.5vw, 1.4rem) 0 0;
  padding: 0;
  gap: .7rem;
  list-style: none;
}

.guest-note {
  padding: .8rem .9rem .7rem;
  background: var(--paper-warm);
  border-left: 2px solid var(--rust);
}
.guest-note__body p { margin: 0 0 .4rem; font-family: var(--display-font); font-size: 1.12rem; font-style: italic; line-height: 1.4; text-wrap: pretty; }
.guest-note__body p:last-child { margin-bottom: 0; }

.guest-note__by {
  display: flex;
  margin: .55rem 0 0;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .2rem .7rem;
  color: var(--stone-light);
  font-family: var(--label-font);
  font-size: .58rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
}

.guest-note__no { color: var(--rust); font-weight: 700; letter-spacing: .12em; }
.guest-note__name { color: var(--stone); }

/* Kept tight on purpose: every line here is a line of somebody else's note
   pushed below the fold, and the notes are what persuade the next person. */
.guest-book__form { width: 100%; display: grid; gap: .5rem; padding-bottom: clamp(.8rem, 2vw, 1.1rem); border-bottom: 1px solid var(--rule); }
.guest-book__form .field { gap: .15rem; }
.guest-book__form .field__label { font-size: .95rem; }
.guest-book__form .field__input { min-height: 2.75rem; padding: .45rem .6rem; font-size: 1rem; }
.guest-book__form textarea.field__input { min-height: 4.4rem; }
.guest-book__form .field__hint { font-size: .78rem; }
.guest-book__form .big-button--go { min-height: 2.4rem; padding: .5rem 1rem; font-size: .76rem; }
.big-button__arrow { display: inline-block; margin-left: .35rem; transition: transform .18s ease; }
.big-button:hover .big-button__arrow { transform: translateX(.25rem); }

.guest-book__error {
  margin: 0;
  padding: .55rem .8rem;
  border-left: 3px solid var(--rust);
  background: var(--paper-light);
  color: var(--rust-dark);
  font-weight: 600;
}

.admin-trash blockquote { margin: .4rem 0; padding-left: .8rem; border-left: 2px solid var(--rule); color: var(--stone); font-style: italic; }

/* These follow the family feed, and on a phone they used to arrive in the same
   paper and the same serif as the notes above them — so two links to other
   reunions read as two more comments. They now sit behind a heavy rule under
   a label that says what they are, and each is a bordered card with a rust
   arrow and an underlined title, which is what a thing you can tap looks like. */
.chapter-nav {
  margin: clamp(2.4rem, 6vw, 4rem) 0 0;
  padding-top: clamp(1rem, 2.5vw, 1.5rem);
  border-top: 3px double var(--rule);
}

.chapter-nav__label {
  margin: 0 0 clamp(.7rem, 2vw, 1rem);
  color: var(--stone);
  font-family: var(--label-font);
  font-size: .58rem;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
}

.chapter-nav__links {
  display: grid;
  gap: clamp(.7rem, 2vw, 1rem);
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
}

.chapter-nav a {
  display: flex;
  padding: clamp(.9rem, 2.5vw, 1.15rem);
  flex-direction: column;
  gap: .35rem;
  border: 1px solid var(--rule);
  background: var(--paper-light);
  color: inherit;
  text-decoration: none;
  transition: border-color .16s ease, background .16s ease;
}

.chapter-nav a:hover,
.chapter-nav a:focus-visible { border-color: var(--rust); background: var(--paper-warm); }
.chapter-nav a:hover .chapter-nav__arrow { transform: translateX(.2rem); }
.chapter-nav a:last-child .chapter-nav__arrow { transform: none; }
.chapter-nav a:last-child:hover .chapter-nav__arrow { transform: translateX(.2rem); }

.chapter-nav__dir { color: var(--rust); font-weight: 700; letter-spacing: .16em; }
.chapter-nav__arrow { display: inline-block; transition: transform .16s ease; }

.chapter-nav__name {
  color: var(--forest);
  font-family: var(--display-font);
  font-size: clamp(1.2rem, 3vw, 1.45rem);
  line-height: 1.15;
  text-decoration: underline;
  text-decoration-color: var(--rule);
  text-decoration-thickness: 1px;
  text-underline-offset: .18em;
}

.chapter-nav a:hover .chapter-nav__name { text-decoration-color: var(--rust); }

/* -------------------------------------------------------------- lightbox */

.lightbox {
  position: fixed;
  z-index: 90;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: rgb(26 25 21 / 96%);
  color: var(--paper-light);
}

.lightbox[hidden] { display: none; }
.motion-ok .lightbox { animation: fade-in .22s ease both; }

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

.lightbox__bar,
.lightbox__foot {
  display: flex;
  padding: .7rem clamp(.8rem, 3vw, 1.6rem);
  align-items: center;
  flex-wrap: wrap;
  gap: .7rem;
}

.lightbox__bar { border-bottom: 1px solid rgb(245 243 237 / 14%); }
.lightbox__foot { padding-bottom: 1rem; border-top: 1px solid rgb(245 243 237 / 14%); }

.lightbox__slug,
.lightbox__position {
  font-family: var(--label-font);
  font-size: .62rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #b4ae96;
}

.lightbox__position { margin-left: auto; color: rgb(245 243 237 / 70%); }

.lightbox button,
.lightbox__download {
  font-family: var(--label-font);
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  cursor: pointer;
}

.lightbox__close {
  min-height: 2.45rem;
  padding: .65rem 1rem;
  border: 1px solid rgb(245 243 237 / 40%);
  background: transparent;
  color: var(--paper-light);
}

.lightbox__close:hover { background: var(--rust); border-color: var(--rust); }

.lightbox__body {
  display: flex;
  min-height: 0;
  padding: clamp(.7rem, 2.5vw, 1.4rem) clamp(.4rem, 2vw, 1.2rem);
  flex: 1 1 auto;
  align-items: center;
  gap: clamp(.4rem, 2vw, 1.1rem);
}

.lightbox__arrow {
  display: grid;
  width: 2.7rem;
  height: 3.6rem;
  flex: 0 0 auto;
  place-items: center;
  border: 1px solid rgb(245 243 237 / 20%);
  background: rgb(245 243 237 / 9%);
  color: var(--paper-light);
  font-size: 1.2rem;
}

.lightbox__arrow:hover { background: rgb(245 243 237 / 20%); }

.lightbox__stage {
  display: flex;
  min-width: 0;
  min-height: 0;
  height: 100%;
  flex: 1 1 auto;
  align-items: center;
  justify-content: center;
}

.lightbox__stage figure {
  display: flex;
  width: 100%;
  height: 100%;
  min-width: 0;
  margin: 0;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .8rem;
  min-height: 0;
}

.lightbox__stage figure[hidden] { display: none; }

.lightbox__stage img,
.lightbox__stage video {
  max-width: 100%;
  max-height: 100%;
  min-height: 0;
  flex: 0 1 auto;
  object-fit: contain;
  background: rgb(222 218 206 / 8%);
}

.lightbox__stage figcaption {
  width: min(48rem, 100%);
  flex: 0 0 auto;
  text-align: center;
}

.lightbox__stage figcaption strong {
  display: block;
  font-family: var(--display-font);
  font-size: clamp(1.2rem, 3vw, 1.7rem);
  font-weight: 600;
  line-height: 1.15;
}

.lightbox__stage figcaption small {
  display: block;
  margin-top: .3rem;
  color: #b4ae96;
  font-family: var(--label-font);
  font-size: .58rem;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.filmstrip {
  display: flex;
  margin: 0;
  padding: 0;
  flex: 1 1 15rem;
  gap: .35rem;
  overflow-x: auto;
  list-style: none;
  scrollbar-width: thin;
}

.filmstrip button {
  width: 3.4rem;
  height: 2.6rem;
  padding: 0;
  flex: 0 0 auto;
  border: 1px solid rgb(245 243 237 / 25%);
  background: rgb(222 218 206 / 10%);
}

.filmstrip img { width: 100%; height: 100%; object-fit: cover; opacity: .7; }
.filmstrip button:hover img { opacity: 1; }
.filmstrip button[aria-current="true"] { border-color: var(--rust); outline: 1px solid var(--rust); }
.filmstrip button[aria-current="true"] img { opacity: 1; }

.lightbox__download {
  min-height: 2.55rem;
  padding: .7rem 1.1rem;
  border: 0;
  background: var(--rust);
  color: #f7f5ee;
  text-decoration: none;
}

.lightbox__download:hover { background: var(--rust-dark); color: #f7f5ee; }

/* ------------------------------------------------------- forms and admin */

.paper-form { width: min(34rem, 100%); padding-top: clamp(1.2rem, 3vw, 2rem); }

/* --- Signing in ---------------------------------------------------------
   One centred card over a pencil study after Vermeer's Astronomer. The drawing
   holds the left of the screen and fades out to the right into the paper, and
   the card sits in what is left. Because the drawing no longer has to be read
   through, it can be shown at something like its real weight. */

.login-screen .site-header,
.login-screen .site-footer { display: none; }

.login-screen .page {
  display: grid;
  width: 100%;
  max-width: none;
  min-height: 100vh;
  min-height: 100dvh;
  /* Symmetric padding, so the card lands on the middle of the screen rather
     than the middle of whatever the drawing left over. */
  padding-left: var(--gutter);
  padding-right: var(--gutter);
  padding-top: clamp(1.5rem, 5vh, 3rem);
  padding-bottom: clamp(1.5rem, 5vh, 3rem);
  place-items: center;
}

/* The study is a fixed panel down the right third, and never a pseudo-element
   at z-index -1 — negative-z-index pseudo-elements are exactly what a browser
   stops painting once something above them takes a backdrop-filter, and that
   is how this drawing came back invisible in the wild. Here it sits at z-index
   0 with the card at 1, which is an ordinary stack, and the card no longer
   asks for a backdrop-filter at all because it now stands on plain paper. */
.login-screen {
  --login-card: 26rem;
  --login-art-gap: clamp(.75rem, 2.5vw, 2.5rem);
  /* The drawing runs from its margin to wherever the centred card begins, so
     it finishes exactly where the card starts instead of being sliced by it. */
  --login-art: clamp(15rem, calc((100vw - var(--login-card)) / 2 - var(--login-art-gap)), 32rem);
  /* Flat paper, not the usual gradient over fibres. The drawing's own sheet was
     multiplied onto this exact colour when it was encoded, so a ground that
     shifts underneath it would give the panel a visible edge. */
  background: var(--paper);
}

.login-screen::after {
  content: "";
  position: fixed;
  z-index: 0;
  inset: 0 auto 0 var(--login-art-gap);
  width: var(--login-art);
  background: url("img/astronomer.webp") no-repeat center / cover;
  /* Solid on the left, gone by the right. The drawing was composited onto the
     site's own paper when it was encoded, so its own light passages already
     match the page and only this edge needed softening. */
  mask-image: linear-gradient(to right, rgb(0 0 0 / 100%) 0%, rgb(0 0 0 / 100%) 45%, rgb(0 0 0 / 0%) 92%);
  -webkit-mask-image: linear-gradient(to right, rgb(0 0 0 / 100%) 0%, rgb(0 0 0 / 100%) 45%, rgb(0 0 0 / 0%) 92%);
  pointer-events: none;
}

.login { position: relative; z-index: 1; display: grid; width: 100%; place-items: center; }

.login__card {
  width: min(var(--login-card, 26rem), 100%);
  padding: clamp(1.7rem, 4.5vw, 2.6rem);
  border: 1px solid var(--rule);
  background: var(--paper-light);
  /* The one shadow on the site. The card has to lift off a drawing rather than
     off paper, and without it the border reads as a hairline box. */
  box-shadow: 0 1px 2px rgb(34 33 29 / 4%), 0 22px 50px -26px rgb(34 33 29 / 28%);
}

/* The masthead is centred; the form below it stays left-aligned, because a
   centred field label reads as decoration and this one has a job. */
.login .login__mark,
.login .login__kicker,
.login .login__lead,
.login .login__admin { text-align: center; }

.login .login__mark { margin: 0; color: var(--forest); font-family: var(--display-font); font-size: clamp(2.3rem, 6vw, 3rem); font-weight: 500; line-height: 1; }
.login .login__kicker { margin: .55rem 0 0; color: var(--rust); font-family: var(--label-font); font-size: .56rem; font-weight: 700; letter-spacing: .24em; text-transform: uppercase; }
.login .login__lead { max-width: 30ch; margin: clamp(1rem, 3vw, 1.35rem) auto 1.1rem; color: var(--stone); font-size: .95rem; line-height: 1.55; text-wrap: pretty; }

.login form { gap: .55rem; }
.login .login__card > form > button[type="submit"] { justify-self: stretch; width: 100%; min-height: 2.9rem; text-align: center; }

.login .login__admin { margin: 1.4rem 0 0; padding-top: 1rem; border-top: 1px solid var(--rule-faint); font-family: var(--label-font); font-size: .55rem; font-weight: 600; letter-spacing: .16em; text-transform: uppercase; }
.login .login__admin a { color: var(--stone-light); text-decoration: none; border-bottom: 1px solid transparent; }
.login .login__admin a:hover, .login .login__admin a:focus-visible { color: var(--rust); border-bottom-color: currentcolor; }
.paper-form h1 { margin: 0 0 1.2rem; color: var(--forest); font-size: clamp(2rem, 4.4vw, 2.9rem); line-height: .95; }
.paper-form form { display: grid; gap: .9rem; padding-top: 1rem; border-top: 1px solid var(--rule); }

.paper-form label {
  display: grid;
  gap: .25rem;
  font-family: var(--label-font);
  font-size: .58rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--stone);
}

.paper-form input,
.paper-form select,
.paper-form textarea {
  width: 100%;
  padding: .5rem .6rem;
  border: 1px solid var(--rule);
  background: var(--paper-light);
  color: var(--ink);
  font: inherit;
  text-transform: none;
  letter-spacing: normal;
}

.paper-form textarea { min-height: 5rem; }

.paper-form button[type="submit"] {
  justify-self: start;
  min-height: 2.6rem;
  padding: .7rem 1.2rem;
  border: 0;
  background: var(--rust);
  color: #f7f5ee;
  font-family: var(--label-font);
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  cursor: pointer;
}

.paper-form button[type="submit"]:hover { background: var(--rust-dark); }
.paper-form [role="alert"] { padding: .5rem .7rem; border-left: 3px solid var(--rust); background: var(--paper-light); }
.contribute-page .privacy-note, .privacy-note { max-width: 46ch; margin-top: 1.6rem; color: var(--stone); font-size: .82rem; line-height: 1.45; }

.admin-inline {
  margin-top: .8rem;
  padding: .7rem;
  border: 1px dashed rgb(43 64 52 / 35%);
  background: rgb(245 243 237 / 80%);
  font-size: .85rem;
}

.admin-inline summary { font-family: var(--label-font); font-size: .58rem; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; cursor: pointer; }
.admin-inline form { display: grid; gap: .5rem; margin-top: .6rem; }
.admin-inline label { display: grid; gap: .2rem; font-family: var(--label-font); font-size: .55rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; }
.admin-inline input, .admin-inline textarea { width: 100%; padding: .4rem; border: 1px solid var(--rule); background: var(--paper-light); font: inherit; }
.admin-inline button { justify-self: start; padding: .35rem .7rem; border: 1px solid var(--rule); background: var(--paper); font-family: var(--label-font); font-size: .55rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; cursor: pointer; }
.admin-inline button:hover { background: var(--rust); border-color: var(--rust); color: #f7f5ee; }
.contact-sheet__item > .admin-inline { display: flex; flex-direction: column; gap: .5rem; }
/* One photograph's controls: a row per job, everything reachable in one tap. */
.admin-row { display: flex; align-items: center; flex-wrap: wrap; gap: .3rem; margin: 0 0 .4rem; }
.admin-row label,
.admin-row__label { flex: 0 0 auto; font-family: var(--label-font); font-size: .55rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--stone-light); }
.admin-row input[type="text"],
.admin-row input:not([type]),
.admin-row select { flex: 1 1 6rem; min-width: 0; min-height: 2.4rem; padding: .3rem .4rem; border: 1px solid var(--rule); background: var(--paper-light); color: var(--ink); font: inherit; font-size: .8rem; }
.admin-row--buttons { gap: .3rem; }
.admin-row form { display: inline; margin: 0; }
.admin-glyph { min-width: 2.4rem; font-size: 1rem; line-height: 1; }
.admin-inline .is-cover { background: var(--forest); border-color: var(--forest); color: var(--paper-light); opacity: 1; cursor: default; }
.admin-inline .admin-danger { border-color: var(--rust); color: var(--rust); }
.admin-inline .admin-danger:hover { background: var(--rust-dark); border-color: var(--rust-dark); }

.admin-trash ul { display: grid; padding: 0; gap: 1rem; list-style: none; }
.admin-trash li { display: grid; padding: 1rem; gap: .65rem; border: 1px solid var(--rule); background: var(--paper-light); }
.admin-trash form { display: flex; align-items: end; flex-wrap: wrap; gap: .6rem; }

/* ---------------------------------------------------------- contribute */

/* Built for a phone held by someone who is not sure they are doing it right:
   one thing per step, targets you cannot miss, and type you do not squint at. */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.contribute-page { width: min(38rem, 100%); padding-top: clamp(1rem, 3vw, 2rem); }
.contribute-page__head h1 { margin: 0 0 .6rem; color: var(--forest); font-size: clamp(2.1rem, 6vw, 3rem); line-height: .95; }
.contribute-page__lead { margin: 0; font-size: 1.08rem; line-height: 1.5; text-wrap: pretty; }

.guide { margin: clamp(1.2rem, 3vw, 1.8rem) 0; padding: clamp(1rem, 3vw, 1.4rem); background: var(--paper-light); border-left: 3px solid var(--flax, var(--stone-light)); }
.guide__title { margin: 0 0 .7rem; font-family: var(--display-font); font-size: 1.3rem; font-style: italic; font-weight: 600; }
.guide__list { margin: 0; padding-left: 1.2rem; }
.guide__list li { margin-bottom: .6rem; font-size: 1rem; line-height: 1.45; }
.guide__list strong { color: var(--forest); }
.guide__note { margin: .9rem 0 0; color: var(--stone); font-size: .9rem; }

.contribute-page__form { display: grid; gap: clamp(1.4rem, 4vw, 2rem); margin-top: clamp(1.2rem, 3vw, 2rem); }
.field { display: grid; gap: .5rem; margin: 0; padding: 0; border: 0; }
.field__step { font-family: var(--label-font); font-size: .55rem; font-weight: 700; letter-spacing: .2em; text-transform: uppercase; color: var(--rust); }
.field__label { font-family: var(--display-font); font-size: 1.35rem; font-weight: 600; }
.field__hint { margin: 0; color: var(--stone); font-size: .92rem; }
.field__hint[data-tone="good"] { color: var(--forest); font-weight: 600; }
.field__hint[data-tone="warn"] { color: var(--rust-dark); font-weight: 600; }

.field__input {
  width: 100%;
  min-height: 3.4rem;
  padding: .75rem .9rem;
  border: 2px solid var(--rule);
  background: var(--paper-light);
  color: var(--ink);
  font: inherit;
  font-size: 1.1rem;
}

.field__input:focus-visible { border-color: var(--rust); outline: none; box-shadow: 0 0 0 3px rgb(140 59 46 / 25%); }
textarea.field__input { min-height: 6rem; }

/* The file input itself is hidden but focusable; the label is the button, so
   the focus ring has to follow the input onto it. */
.big-button {
  display: block;
  width: 100%;
  min-height: 3.9rem;
  padding: 1.05rem 1.2rem;
  border: 2px solid var(--forest);
  background: var(--forest);
  color: var(--paper-light);
  font-family: var(--label-font);
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-align: center;
  text-transform: uppercase;
  cursor: pointer;
}

.big-button:hover { background: var(--rust); border-color: var(--rust); }
.field--files input:focus-visible + .big-button { outline: .18rem solid var(--rust); outline-offset: .2rem; }
.big-button--go { background: var(--rust); border-color: var(--rust); font-size: .92rem; }
.big-button--go:hover { background: var(--rust-dark); border-color: var(--rust-dark); }
.big-button--go:disabled { background: var(--tint); border-color: var(--rule); color: var(--stone); cursor: not-allowed; }

.field--files { padding: 1rem; border: 2px dashed var(--rule); background: var(--paper-light); }
.field--files[data-dragging] { border-color: var(--rust); background: var(--paper-warm); }

.picked { display: grid; margin: .3rem 0 0; padding: 0; gap: .7rem; grid-template-columns: repeat(auto-fill, minmax(min(10rem, 100%), 1fr)); list-style: none; }
.picked li { display: grid; gap: .3rem; padding: .5rem; background: var(--paper); border: 1px solid var(--rule-faint); }
.picked li[data-too-big] { border-color: var(--rust); background: #f7e9e5; }
.picked img { width: 100%; aspect-ratio: 1; object-fit: cover; background: var(--tint); }
.picked li > img, .picked li > .picked__badge { border: 1px solid var(--rule-faint); }
.picked__badge { display: grid; aspect-ratio: 1; place-items: center; background: var(--tint); font-family: var(--label-font); font-size: .58rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--stone); }
.picked p { margin: 0; font-size: .76rem; line-height: 1.2; overflow-wrap: anywhere; }
.picked small { color: var(--stone-light); font-size: .7rem; }
.picked img { transition: transform .18s ease; }
.picked__note { width: 100%; min-height: 2.6rem; padding: .35rem .45rem; border: 1px solid var(--rule); background: var(--paper-light); color: var(--ink); font: inherit; font-size: .8rem; }
.picked__note:focus-visible { border-color: var(--rust); outline: none; box-shadow: 0 0 0 2px rgb(140 59 46 / 25%); }
.picked__controls { display: flex; gap: .3rem; }
.picked__turn { min-width: 2.6rem; min-height: 2.6rem; flex: 0 0 auto; border: 1px solid var(--rule); background: var(--paper-light); color: var(--forest); font-size: 1.1rem; line-height: 1; cursor: pointer; }
.picked__turn:hover { background: var(--forest); border-color: var(--forest); color: var(--paper-light); }
.picked__controls .picked__remove { flex: 1 1 auto; }
.picked__remove { min-height: 2.6rem; padding: .3rem; border: 1px solid var(--rule); background: transparent; color: var(--stone); font-family: var(--label-font); font-size: .55rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; cursor: pointer; }
.picked__remove:hover { background: var(--rust); border-color: var(--rust); color: var(--paper-light); }

.field--years legend { display: grid; gap: .5rem; margin-bottom: .6rem; padding: 0; }
.year-chips { display: grid; gap: .6rem; grid-template-columns: repeat(auto-fit, minmax(min(9rem, 100%), 1fr)); }

.year-chips label {
  display: grid;
  min-height: 4.2rem;
  padding: .7rem .8rem;
  align-content: center;
  gap: .15rem;
  border: 2px solid var(--rule);
  background: var(--paper-light);
  cursor: pointer;
}

.year-chips label strong { color: var(--forest); font-family: var(--display-font); font-size: 1.6rem; font-weight: 600; line-height: 1; font-variant-numeric: lining-nums; }
.year-chips label span { color: var(--stone); font-family: var(--display-font); font-size: 1rem; font-style: italic; line-height: 1.15; }
.year-chips label:hover { border-color: var(--rust); }
.year-chips input:checked + label { border-color: var(--rust); background: var(--paper-warm); box-shadow: inset 0 0 0 2px var(--rust); }
.year-chips input:focus-visible + label { outline: .18rem solid var(--rust); outline-offset: .2rem; }

.field--optional { padding: .9rem 1rem; border: 1px solid var(--rule-soft); background: var(--paper-light); }
.field--optional summary { display: flex; min-height: 2.75rem; align-items: center; gap: .5rem; flex-wrap: wrap; font-family: var(--display-font); font-size: 1.1rem; font-weight: 600; cursor: pointer; }
.field--optional summary span { color: var(--stone-light); font-family: var(--label-font); font-size: .58rem; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; }
.field--optional > .field__label { display: block; margin: .8rem 0 .4rem; font-size: 1.05rem; }

.done { scroll-margin-top: 5.5rem; padding: clamp(1.4rem, 4vw, 2rem); background: var(--paper-light); border: 2px solid var(--forest); }
.done:focus-visible { outline: .18rem solid var(--rust); outline-offset: .25rem; }
.done__mark { margin: 0 0 .4rem; color: var(--forest); font-size: 2.6rem; line-height: 1; }
.done__title { margin: 0 0 .9rem; color: var(--forest); font-family: var(--display-font); font-size: clamp(1.7rem, 5vw, 2.3rem); font-weight: 600; line-height: 1.05; }
.done__what { margin: 0 0 .8rem; font-size: 1.02rem; line-height: 1.5; text-wrap: pretty; }
.done__note { margin: 0 0 .8rem; color: var(--stone); font-size: .92rem; line-height: 1.45; text-wrap: pretty; }
.done__actions { display: grid; gap: .7rem; margin-top: 1.2rem; }
.done__actions .big-button { text-decoration: none; display: flex; align-items: center; justify-content: center; }
.big-button--quiet { background: transparent; border-color: var(--rule); color: var(--stone); }
.big-button--quiet:hover { background: var(--paper-warm); border-color: var(--rust); color: var(--rust); }

.upload-status { margin: 0; min-height: 1.4rem; font-size: 1rem; }
.upload-status[data-tone="good"] { color: var(--forest); font-weight: 600; }
.upload-status[data-tone="warn"] { color: var(--rust-dark); font-weight: 600; }
.upload-progress { height: .6rem; background: var(--tint); }
.upload-progress span { display: block; width: 0; height: 100%; background: var(--forest); transition: width .2s ease; }

/* Narrower than this and there is no room beside the card for the drawing, so
   it goes back to lying under the whole screen with the paper washed over it —
   the same drawing, knocked back far enough to read through. */
@media (max-width: 940px) {
  .login-screen .page { padding-left: var(--gutter); padding-right: var(--gutter); }
  .login-screen::after {
    inset: 0;
    width: auto;
    left: 0;
    background:
      radial-gradient(58% 40% at 50% 48%, rgb(237 234 227 / 93%) 0%, rgb(237 234 227 / 66%) 60%, rgb(237 234 227 / 34%) 100%),
      linear-gradient(rgb(237 234 227 / 58%), rgb(237 234 227 / 28%) 28%, rgb(237 234 227 / 28%) 72%, rgb(237 234 227 / 62%)),
      url("img/astronomer.webp") no-repeat center / cover;
    mask-image: none;
    -webkit-mask-image: none;
  }
}

/* Three across stops paying once the rail has taken its 21rem: below this a
   third column buys nothing but smaller photographs. */
@media (max-width: 1100px) {
  .contact-sheet__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 760px) {
  .contribute-page__form { gap: 1.6rem; }
  /* Header controls are the smallest thing on a phone; give them a real target. */
  .contribute,
  .signout button { display: inline-flex; min-height: 2.75rem; align-items: center; }

  /* Six reunions have to sit on one line of an iPhone held upright, so the
     chips give up their padding rather than their border — the border is the
     part that says they can be pressed. */
  .year-tabs ol { gap: .25rem; }

  .year-tabs a {
    display: inline-flex;
    min-height: 1.95rem;
    padding: .15rem .5rem;
    align-items: center;
    font-size: .55rem;
    letter-spacing: .06em;
  }
  .field__label { font-size: 1.25rem; }
  .year-chips { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ----------------------------------------------------------- analytics */

.admin-page { padding-top: clamp(1rem, 2.5vw, 1.8rem); }
.admin-page__head { padding-bottom: 1rem; border-bottom: 1px solid var(--rule); }
.admin-page h1 { margin: 0 0 .5rem; color: var(--forest); font-size: clamp(1.9rem, 4vw, 2.8rem); line-height: .95; }

.admin-page__note {
  max-width: 68ch;
  margin: .6rem 0 0;
  color: var(--stone);
  font-size: .88rem;
  line-height: 1.45;
}

.admin-page__note code { font-size: .92em; }

.admin-windows { display: flex; margin-top: .9rem; flex-wrap: wrap; gap: .2rem 1rem; }

.admin-windows a {
  color: var(--stone);
  font-family: var(--label-font);
  font-size: .58rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  text-decoration: none;
}

.admin-windows a:hover { color: var(--rust); }
.admin-windows a[aria-current="page"] { color: var(--rust); text-decoration: underline; text-underline-offset: .35em; }

.stat-row {
  display: grid;
  margin: 0;
  padding: 1.1rem 0;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(9rem, 100%), 1fr));
  border-bottom: 1px solid var(--rule);
  list-style: none;
}

.stat-row strong {
  display: block;
  color: var(--forest);
  font-family: var(--display-font);
  font-size: clamp(1.8rem, 4vw, 2.6rem);
  font-weight: 600;
  line-height: 1;
  font-variant-numeric: lining-nums tabular-nums;
}

.stat-row span {
  display: block;
  margin-top: .3rem;
  color: var(--stone-light);
  font-family: var(--label-font);
  font-size: .58rem;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
}

.panel { padding: clamp(1.1rem, 2.5vw, 1.8rem) 0; border-bottom: 1px solid var(--rule-soft); }
.panel h2 { margin: 0 0 .9rem; font-family: var(--display-font); font-size: 1.5rem; font-weight: 600; }
.panel__empty, .panel__note { margin: .6rem 0 0; color: var(--stone); font-size: .86rem; }
.panel-pair { display: grid; gap: 0 clamp(1.5rem, 4vw, 3rem); grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr)); }

/* Daily visits. A bar per day including the quiet ones, so a gap reads as a
   gap rather than being closed up. */
.trend {
  display: flex;
  height: 7rem;
  margin: 0;
  padding: 0;
  align-items: flex-end;
  gap: 1px;
  border-bottom: 1px solid var(--rule);
  list-style: none;
}

.trend span { display: block; min-width: 2px; flex: 1 1 auto; background: var(--forest); }
.trend span:hover { background: var(--rust); }

.trend__scale {
  display: flex;
  margin: .4rem 0 0;
  justify-content: space-between;
  gap: 1rem;
  color: var(--stone-light);
  font-family: var(--label-font);
  font-size: .55rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.visit-map {
  display: block;
  width: 100%;
  height: auto;
  margin-bottom: .8rem;
  background: var(--paper-light);
  border: 1px solid var(--rule-faint);
}

.visit-map path { fill: var(--tint); stroke: var(--stone-light); stroke-width: .8; }
.visit-map circle { fill: var(--rust); fill-opacity: .55; stroke: var(--rust-dark); stroke-width: 1; }

.admin-page table { width: 100%; margin-top: .5rem; border-collapse: collapse; font-size: .88rem; }
.admin-page caption { margin-bottom: .4rem; color: var(--stone-light); font-family: var(--label-font); font-size: .58rem; font-weight: 600; letter-spacing: .18em; text-align: left; text-transform: uppercase; }
.admin-page th { color: var(--stone-light); font-family: var(--label-font); font-size: .55rem; font-weight: 700; letter-spacing: .14em; text-align: left; text-transform: uppercase; }
.admin-page th, .admin-page td { padding: .4rem .6rem .4rem 0; border-bottom: 1px solid var(--rule-faint); vertical-align: baseline; }
.admin-page td:not(:first-child), .admin-page th:not(:first-child) { width: 6rem; text-align: right; font-variant-numeric: tabular-nums; }
.admin-page tbody tr:hover { background: var(--paper-warm); }
.admin-page td span { color: var(--stone); font-style: italic; }
.admin-page code { color: var(--stone); font-size: .92em; }

/* -------------------------------------------------------------- footer */

.site-footer {
  margin-top: clamp(1.4rem, 3vw, 2.4rem);
  padding: 1rem var(--gutter) 2rem;
  border-top: 1px solid var(--rule);
}

.site-footer > div {
  display: flex;
  width: min(var(--shell), 100%);
  margin: 0 auto;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 1rem;
}

.site-footer p {
  margin: 0;
  color: var(--stone);
  font-family: "Crimson Pro", Georgia, serif;
  font-size: .92rem;
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
}

/* A bonus doorway, further back than any reunion: the family-history archive
   hangs off the footer as one quiet link. It shares the footer's label voice
   and sits apart from the two end notes, with a small mark and a rust tint so
   the eye finds it without being pulled to it. */
.site-footer .footer-aside {
  font-family: var(--label-font);
  font-size: .58rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
}

.site-footer .footer-aside a {
  color: var(--rust);
  text-decoration: none;
  border-bottom: 1px dotted currentColor;
  padding-bottom: .1em;
}

.site-footer .footer-aside a::before {
  content: "\2726\00a0";
  color: var(--stone-light);
}

.site-footer .footer-aside a:hover,
.site-footer .footer-aside a:focus-visible {
  color: var(--rust-dark);
  border-bottom-style: solid;
}

.site-footer .footer-mark {
  margin-left: auto;
  color: var(--stone-light);
  font-family: var(--label-font);
  font-size: .58rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
}

/* -------------------------------------------------------------- narrow */

@media (max-width: 760px) {
  :root { font-size: 17px; }

  .header-bar { padding-block: .45rem; row-gap: .3rem; }
  .wordmark { margin-right: .5rem; }
  .wordmark__kicker { display: none; }
  .year-tabs { order: 5; width: 100%; margin-inline: calc(var(--gutter) * -1); padding-inline: var(--gutter); }
  .admin-chrome { order: 6; width: 100%; }

  .lead-photo--empty { aspect-ratio: 4 / 3; }
  .masthead h1 { max-width: none; }

  .chapter-opener { grid-template-columns: minmax(0, 1fr); }
  /* Below the split the feed follows the photographs, so the invitation earns
     its place again. */
  .chapter-body { grid-template-columns: minmax(0, 1fr); margin-top: clamp(1.4rem, 5vw, 2rem); }
  .chapter-body__feed { position: static; max-height: none; padding-left: 0; padding-top: clamp(1.6rem, 4vw, 2.2rem); overflow: visible; border-left: 0; border-top: 1px solid var(--rule); }
  /* On a phone the invitation and the Add Your Photos button ended up stacked
     one on the other, and the sentences beside the Family Feed button read as
     if they might belong to either. So the invitation becomes one bordered
     block, in the same warm paper and rust hairline the notes themselves use:
     its words sit with its own button, and there is no question where it ends
     and the photographs begin. */
  .feed-invite[hidden] { display: grid !important; }

  .feed-invite {
    gap: .7rem;
    padding: clamp(.85rem, 3.5vw, 1.1rem);
    grid-template-columns: minmax(0, 1fr);
    justify-items: start;
    background: var(--paper-warm);
    border-left: 2px solid var(--rust);
  }

  /* The sentences make the case; the button answers them. */
  .feed-invite__text { order: 1; }
  .feed-invite__button { order: 2; }
  .login__card { padding: clamp(1.4rem, 6vw, 1.9rem); }
  /* 2.4rem is fine under a mouse; a finger needs the full 44px back. */
  .guest-book__form .big-button--go,
  .plates-action a { min-height: 2.6rem; }
  .feed-invite__button { min-height: 2.6rem; padding: .5rem .9rem; gap: .35rem; font-size: .64rem; letter-spacing: .1em; }
  .feed-invite__lead { font-size: 1.05rem; }
  .feed-invite__note { font-size: .82rem; }
  .chapter-hero img { max-height: 20rem; }
  .home-split { grid-template-columns: minmax(0, 1fr); }
  .chapter-row { grid-template-columns: 3.4rem minmax(0, 1fr) auto; padding-block: .55rem; }
  .chapter-row__no,
  .chapter-row__meta,
  .chapter-row__go-word { display: none; }
  /* With the word gone, the arrow is the whole signal; give it some size. */
  .chapter-row__arrow { font-size: 1.2rem; }
  .chapter-row__plate { width: 3.4rem; }

  .chapter-nav__links { grid-template-columns: 1fr; }

  .contact-sheet__grid { grid-template-columns: repeat(auto-fill, minmax(min(9.5rem, 100%), 1fr)); }
  .lightbox__arrow { width: 2.2rem; height: 3rem; }
  .lightbox__stage figcaption strong { font-size: 1.1rem; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}
