/* Norwich Astro · folio design, the main site (home, About, Contact).
   Self-contained: no other token sheet. The second token group maps the
   variable names used by the verbatim .pswp__custom-caption block onto
   folio values. */

:root {
  --ground: oklch(15% 0.008 40);
  --ground-2: oklch(20% 0.009 42);
  --ink: oklch(89% 0.012 55);
  --ink-muted: oklch(62% 0.012 50);
  --hairline: oklch(30% 0.01 45);
  --accent: oklch(62% 0.14 25);

  /* quicknav widget mapping */
  --qn-bg: var(--ground-2);
  --qn-ink: var(--ink);
  --qn-rule: var(--hairline);
  --qn-accent: var(--accent);
  --qn-font-size: 0.875rem;

  /* tokens consumed by the verbatim lightbox caption block */
  /* The strip: one title line and one row of controls, at any width. In pixels,
     and read by src/js/folio.js, which asks the lightbox to keep exactly this
     much clear: the reservation and the strip cannot then disagree. Tall enough
     that the padding below the controls is real rather than overrun by the
     content, and set so that gap matches the one above the photograph. */
  --lightbox-cap: 96px;
  /* The data panel, opened from the strip. src/js/folio.js reads both numbers
     and asks the lightbox to reserve exactly that much room, so the panel never
     draws over the photograph. Bare numbers of pixels, because that is what the
     lightbox works in and what the query below has to switch on.
     Wide enough, and the panel goes in the empty margin beside the image, where
     it costs the photograph nothing at all: the image is limited by the height
     of the window, so the width it is not using is free. Narrow, and there is
     no margin to use, so the panel sits under the image and the image gives up
     the height for as long as the panel is open. */
  --lightbox-details-side: 0;
  --lightbox-details-below: 208;
  --page-gutter: clamp(1rem, 3vw, 2.5rem);
  --space-xs: 0.5rem;
  --space-2xs: 0.25rem;
  --space-sm: 0.75rem;
  --space-md: 1rem;
  /* 0.8rem is 12.8px, which clears the 12px floor below which small print
     stops being comfortably readable on a phone. */
  --text-xs: 0.8rem;
  --text-sm: 0.875rem;
  --text-base: 0.9375rem;
  --dur-short: 220ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --font-display: "Instrument Serif", serif;
  --font-mono: "Geist", system-ui, sans-serif;
  --color-muted: oklch(62% 0.012 50);
  --color-accent: oklch(62% 0.14 25);
  --rule-hair: 1px;
}
@font-face {
  font-family: "Instrument Serif";
  src: url("/assets/fonts/alt/instrument-serif-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Instrument Serif";
  src: url("/assets/fonts/alt/instrument-serif-400-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Geist";
  src: url("/assets/fonts/alt/geist-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { overflow-x: clip; }
html {
  scroll-behavior: smooth;
  /* One number sets the size of everything. Every size on this site is in rem,
     type and spacing alike, so raising the root raises them together and the
     proportions between them do not move. A percentage rather than a pixel
     value, so a reader who has set a larger default in their browser keeps it.
     The container width is in px and vw and does not follow, which is the
     point: the text grows inside the same column. */
  font-size: 112%;
}
body {
  background: var(--ground);
  color: var(--ink);
  font-family: "Geist", system-ui, sans-serif;
  font-size: 1rem;
  line-height: 1.5;
}
a { color: inherit; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
img { display: block; width: 100%; height: auto; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: clip;
  clip-path: inset(50%); white-space: nowrap;
}
.skip {
  position: absolute;
  left: var(--page-gutter);
  top: 0;
  transform: translateY(-150%);
  background: var(--ground-2);
  color: var(--ink);
  padding: 0.5rem 1rem;
  z-index: 200;
  text-decoration: none;
  white-space: nowrap;
  transition: transform var(--dur-short) var(--ease-out);
}
.skip:focus-visible { transform: translateY(0); }
/* The one thing that decides how much of the window the site uses.
   min(94vw, 1680px) leaves 1600px of content at the top end, and 1600 is not
   an arbitrary number: the widest rendition of every photograph is 3200px, and
   a retina screen asks for twice the CSS width, so 1600 is exactly the point
   where a large display is still served at full resolution by files that
   already exist. Going wider means adding a 4096px rendition to every image.
   Prose keeps its own much smaller line lengths further down; a 1600px line of
   text would be unreadable. */
.wrap {
  max-width: min(94vw, 1680px);
  margin: 0 auto;
  padding: 0 clamp(1rem, 3vw, 2.5rem);
}
.util-nav {
  position: absolute;
  top: 1.1rem;
  right: clamp(1rem, 3vw, 2.5rem);
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.4rem clamp(1rem, 2.5vw, 1.8rem);
}
/* The padding raises the touch area of these links to 24px; the matching
   negative margin keeps their outer box the size the text alone had, so the
   nav rows, the masthead and everything under it stay exactly where they
   were. The same pair is on the category nav and the footer social row. */
.util-nav a {
  font-size: 0.75rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink-muted);
  white-space: nowrap;
  padding: 0.22rem 0;
  margin: -0.22rem 0;
}
.util-nav a:hover { color: var(--ink); }
.util-nav a[aria-current="page"] { color: var(--ink); }

/* On narrow screens the utility links leave the corner and centre above the
   wordmark, wrapping like the category row. */
@media (max-width: 759px) {
  .util-nav {
    position: static;
    justify-content: center;
    margin-bottom: 0.9rem;
  }
}
.masthead {
  position: relative;
  text-align: center;
  padding: clamp(3.5rem, 8vw, 6rem) 0 0;
  animation: rise 0.9s cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: translateY(0); }
}
/* On the home page the wordmark is the page heading. The wrapper takes the
   masthead's own font metrics, so the line box it makes is the one the bare
   link made and nothing on the page moves. */
.masthead-title { font: inherit; }
.wordmark {
  font-family: "Instrument Serif", serif;
  font-weight: 400;
  font-size: clamp(2.4rem, 8.5vw, 6rem);
  letter-spacing: 0.04em;
  line-height: 1.05;
  text-decoration: none;
  white-space: nowrap;
  display: inline-block;
}
/* Under the wordmark, above the rule: quiet, so it reads as a subtitle rather
   than competing with the masthead. */
.tagline {
  margin-top: clamp(0.6rem, 1.6vw, 1rem);
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}

.double-rule {
  margin: clamp(1.2rem, 3vw, 2rem) auto 0;
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
  height: 5px;
}
.cats-nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  column-gap: clamp(1.2rem, 3vw, 2.5rem);
  row-gap: 0.5rem;
  padding: 1.1rem 0 0;
}
.cats-nav a {
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink-muted);
  white-space: nowrap;
  padding: 0.22rem 0;
  margin: -0.22rem 0;
}
.cats-nav a:hover { color: var(--ink); }
.plate-featured { margin-top: clamp(2.2rem, 5vw, 3.5rem); }
.cat {
  margin-top: clamp(4rem, 9vw, 7.5rem);
  scroll-margin-top: 2rem;
}
.cat-head { margin-bottom: clamp(1.6rem, 4vw, 2.8rem); }
.cat-title {
  font-family: "Instrument Serif", serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(2.6rem, 7vw, 5.5rem);
  line-height: 1;
  letter-spacing: 0.01em;
}
.cat-count {
  font-family: "Geist", system-ui, sans-serif;
  font-style: normal;
  font-size: clamp(0.85rem, 1.4vw, 1.05rem);
  letter-spacing: 0.08em;
  color: var(--accent);
  vertical-align: super;
  margin-left: 0.5em;
}
.cat-rule {
  margin-top: clamp(0.9rem, 2vw, 1.4rem);
  border-top: 1px solid var(--accent);
}
.g-link { display: block; text-decoration: none; }
.plate-full { margin-bottom: clamp(1.8rem, 4vw, 3rem); }
figcaption {
  display: flex;
  align-items: baseline;
  gap: 0.7em;
  margin-top: 0.7rem;
}
.plate-no {
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  color: var(--ink-muted);
}
.plate-title {
  font-family: "Instrument Serif", serif;
  font-size: 0.92rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink);
}
/* Rows of two plates. Each plate's width share is proportional to its aspect
   ratio (flex-grow = ar, basis 0), so both images in a row render at exactly
   the same height with no cropping, whatever their shapes. */
.folio-rows {
  display: grid;
  row-gap: clamp(2.2rem, 5vw, 3.6rem);
}
.f-row {
  display: flex;
  align-items: flex-start;
  gap: clamp(0.9rem, 2vw, 1.4rem);
}
.f-row .plate { flex: var(--fg, 1) 1 0%; min-width: 0; }
@media (max-width: 759px) {
  .f-row { flex-direction: column; gap: clamp(2.2rem, 5vw, 3.6rem); }
  .f-row .plate { flex: none; width: 100%; }
}
/* Closing plate for the solar system model. The section header reuses the
   cat-head pattern at the image-page title size, so the model never reads
   louder than a category chapter, and the line sits under the accent rule.
   The anchor wraps heading, line and image: all three open the model. */
.orrery-link {
  display: block;
  text-decoration: none;
  color: inherit;
}
.orrery-link .cat-title { font-size: clamp(1.9rem, 4.5vw, 3.6rem); }
.orrery-line {
  margin-top: clamp(0.9rem, 2vw, 1.4rem);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  line-height: 1.7;
  color: var(--ink-muted);
  max-width: 72ch;
}
.orrery-link:hover .cat-title { color: var(--accent); }
.orrery-link:hover .orrery-line { color: var(--ink); }

/* About portrait: centred under the masthead rule, never wider than its own
   pixels so it is not upscaled. */
.portrait {
  margin: clamp(2.5rem, 6vw, 4rem) auto clamp(1.5rem, 4vw, 2.5rem);
  max-width: 620px;
}
.portrait img { width: 100%; height: auto; }

/* ---------- per-image pages (/image/<slug>/) ---------- */

.image-page { margin-top: clamp(2.5rem, 6vw, 4.5rem); }
.image-title {
  font-family: "Instrument Serif", serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.9rem, 4.5vw, 3.6rem);
  line-height: 1.05;
  letter-spacing: 0.01em;
  padding-bottom: clamp(0.9rem, 2vw, 1.4rem);
  border-bottom: 1px solid var(--accent);
}
.image-page .plate { margin-top: clamp(1.8rem, 4vw, 3rem); margin-bottom: 0; }
.image-desc {
  margin-top: clamp(1.4rem, 3vw, 2rem);
  color: var(--ink);
  font-size: 0.95rem;
  line-height: 1.7;
  max-width: 74ch;
}
/* the Redbubble link: the contact button treatment, as a link */
.image-buy { margin-top: clamp(1.6rem, 4vw, 2.4rem); }
.image-buy a {
  display: inline-block;
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  border: 1px solid var(--accent);
  color: var(--ink);
  padding: 0.7rem 1.4rem;
  transition: background-color var(--dur-short) var(--ease-out), color var(--dur-short) var(--ease-out);
}
.image-buy a:hover {
  background: var(--accent);
  color: var(--ground);
}
/* ---------- blog ---------- */

/* Scoped to the article: .byline is already the site footer's class, and an
   unscoped rule here restyled the footer on every page. */
.blog .byline {
  color: var(--ink-muted);
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  margin-top: -0.4rem;
}
/* Restored WordPress articles carry figures with captions and inline images.
   They are constrained to the prose column like everything else. */
.blog figure {
  margin: clamp(1.6rem, 4vw, 2.4rem) 0;
}
.blog figure img {
  width: 100%;
  height: auto;
  border: 1px solid var(--hairline);
}
.blog figcaption {
  margin-top: 0.5rem;
  color: var(--ink-muted);
  font-size: 0.8rem;
  line-height: 1.6;
}
.blog ul {
  padding-left: 1.2rem;
  line-height: 1.9;
}

.blog-list {
  list-style: none;
  padding: 0;
}
.blog-list li {
  padding: clamp(1.2rem, 3vw, 1.8rem) 0;
  border-bottom: 1px solid var(--hairline);
}
.blog-list li > a {
  font-family: var(--font-display);
  font-size: clamp(1.2rem, 3vw, 1.5rem);
  text-decoration: none;
}
.blog-list li > span {
  display: block;
  margin-top: 0.3rem;
  color: var(--ink-muted);
  font-size: 0.8rem;
  letter-spacing: 0.08em;
}
.blog-list li > p {
  margin-top: 0.5rem;
  color: var(--ink-muted);
}

/* ---------- solar system question pages ---------- */

/* The figure block borrows the image data block's grid so a number on one of
   these pages reads the same way as a number under a photograph. */
.fig {
  margin: clamp(1.4rem, 3vw, 2rem) 0;
  border-top: 1px solid var(--hairline);
}
.fig > div {
  display: grid;
  grid-template-columns: 14rem 1fr;
  gap: 0.3rem 1.5rem;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--hairline);
}
.fig dt {
  font-size: 0.75rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-muted);
  padding-top: 0.2rem;
}
.fig dd {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.7;
}
.fig dd b {
  font-weight: 600;
}
/* The qualifier that makes the number honest: which date it was true on, or
   what the unit means. Quieter than the number, never hidden. */
.fig dd span {
  color: var(--ink-muted);
  font-size: 0.85rem;
}
@media (max-width: 32rem) {
  .fig > div { grid-template-columns: 1fr; gap: 0.15rem; }
}

/* The link into the model is the point of the page, so it is a control rather
   than another sentence with a link in it. */
.model-link {
  margin: clamp(1.6rem, 4vw, 2.4rem) 0;
}
.model-link a {
  display: inline-block;
  padding: 0.7rem 1.4rem;
  border: 1px solid var(--accent);
  border-radius: 2px;
  color: var(--accent);
  text-decoration: none;
  font-size: 0.85rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.model-link a:hover {
  background: var(--accent);
  color: var(--ground);
}

.sources {
  padding-left: 1.1rem;
  font-size: 0.9rem;
  line-height: 1.9;
  color: var(--ink-muted);
}
.sources a { color: inherit; }
.sources a:hover { color: var(--ink); }

.img-data {
  margin-top: clamp(1.8rem, 4vw, 2.6rem);
  border-top: 1px solid var(--hairline);
}
.img-data > div {
  display: grid;
  grid-template-columns: 9rem 1fr;
  gap: 0.3rem 1.5rem;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--hairline);
}
.img-data dt {
  font-size: 0.75rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-muted);
  padding-top: 0.2rem;
}
.img-data dd {
  font-size: 0.875rem;
  letter-spacing: 0.04em;
  line-height: 1.7;
  color: var(--ink);
}
@media (max-width: 40rem) {
  .img-data > div { grid-template-columns: 1fr; }
}
.img-nav {
  margin-top: clamp(2rem, 5vw, 3rem);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.6rem 1.5rem;
  flex-wrap: wrap;
}
.img-nav a {
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink-muted);
  padding: 0.22rem 0;
  margin: -0.22rem 0;
}
.img-nav a:hover { color: var(--ink); }
.img-nav a[rel="next"] { text-align: right; }
.img-nav .img-nav__cat { color: var(--accent); }

/* ---------- prose pages (About, Contact) ---------- */

.prose {
  max-width: 54rem;
  margin: clamp(2.5rem, 6vw, 4.5rem) auto 0;
}
.prose h1 {
  font-family: "Instrument Serif", serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(2.6rem, 7vw, 5.5rem);
  line-height: 1;
  letter-spacing: 0.01em;
  padding-bottom: clamp(0.9rem, 2vw, 1.4rem);
  border-bottom: 1px solid var(--accent);
}
.prose h2 {
  font-family: "Instrument Serif", serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.9rem, 4.5vw, 3rem);
  line-height: 1.1;
  margin-top: clamp(2rem, 4.5vw, 3rem);
}
.prose p {
  margin-top: 1.1rem;
  color: var(--ink-muted);
  font-size: 0.95rem;
  line-height: 1.7;
  max-width: 65ch;
}
.prose > p:first-of-type {
  margin-top: clamp(1.6rem, 4vw, 2.8rem);
  color: var(--ink);
}

/* the equipment section on About: folio section header, full plate, list */
.rig { margin-top: clamp(4rem, 9vw, 7.5rem); }
/* One block per setup, the name above its list with clear air over it so the
   three setups read apart at a glance. */
.rig__groups {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 0 clamp(1.5rem, 4vw, 3rem);
}
.rig__name {
  margin-top: clamp(2rem, 4vw, 2.8rem);
  font-family: "Instrument Serif", serif;
  font-weight: 400;
  font-size: 1.35rem;
  letter-spacing: 0.03em;
}
.rig__list {
  list-style: none;
  margin-top: 0.6rem;
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  line-height: 1.9;
  color: var(--ink-muted);
}

/* ---------- contact form ---------- */

/* Third element on this site to need this stated: display below is an author
   rule and beats the user-agent [hidden], so without it the form cannot be
   replaced by the confirmation after a message is sent. See .consent and
   .subscribe__form. */
.contact[hidden] { display: none; }
/* Says what happened after a send: sending, sent, or how to reach him if it
   did not go through. Empty until the handler writes to it, so it takes no
   room on a page nobody has submitted. */
.form-status:empty { display: none; }
.form-status {
  margin-top: 0.8rem;
  color: var(--ink-muted);
  font-size: 0.9rem;
  line-height: 1.6;
}
.contact {
  display: grid;
  gap: 0.4rem;
  max-width: 34rem;
  margin-top: clamp(1.6rem, 4vw, 2.4rem);
}
.contact label {
  font-size: 0.75rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-top: 1rem;
}
.contact input, .contact textarea {
  background: var(--ground-2);
  border: 1px solid var(--hairline);
  color: var(--ink);
  font: inherit;
  padding: 0.7rem 1rem;
  min-width: 0;
}
.contact input:focus-visible, .contact textarea:focus-visible,
.subscribe__form input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 0;
  border-color: var(--accent);
}
.contact button {
  justify-self: start;
  margin-top: 1.4rem;
  font-family: "Geist", system-ui, sans-serif;
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  background: none;
  border: 1px solid var(--accent);
  color: var(--ink);
  padding: 0.7rem 1.4rem;
  cursor: pointer;
  transition: background-color var(--dur-short) var(--ease-out), color var(--dur-short) var(--ease-out);
}
.contact button:hover {
  background: var(--accent);
  color: var(--ground);
}

.subscribe {
  max-width: 40rem;
  margin: clamp(4rem, 9vw, 7.5rem) auto 0;
  text-align: center;
}
.subscribe h2 {
  font-family: "Instrument Serif", serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.9rem, 4.5vw, 3rem);
  line-height: 1.1;
}
.subscribe p {
  margin-top: 0.9rem;
  color: var(--ink-muted);
  font-size: 0.92rem;
}
/* Same reason as .consent[hidden] above: display:flex here is an author rule
   and would beat the user-agent [hidden], so the form could not be replaced
   by the confirmation after a successful signup. */
.subscribe__form[hidden] { display: none; }
.subscribe__form {
  margin-top: 1.6rem;
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
  justify-content: center;
}
.subscribe__form input {
  flex: 1 1 16rem;
  min-width: 0;
  max-width: 24rem;
  background: var(--ground-2);
  border: 1px solid var(--hairline);
  color: var(--ink);
  font: inherit;
  padding: 0.7rem 1rem;
}
.subscribe__form input::placeholder { color: var(--ink-muted); }
.subscribe__form button {
  font-family: "Geist", system-ui, sans-serif;
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  background: none;
  border: 1px solid var(--hairline);
  color: var(--ink);
  padding: 0.7rem 1.4rem;
}
.subscribe__form input:disabled,
.subscribe__form button:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}
.subscribe__note {
  margin-top: 0.9rem;
  font-size: 0.75rem;
  letter-spacing: 0.06em;
}
footer {
  margin: clamp(5rem, 10vw, 8rem) 0 0;
  padding: clamp(2rem, 5vw, 3.5rem) 0 clamp(2.5rem, 6vw, 4rem);
  border-top: 1px solid var(--hairline);
  text-align: center;
}
.closing {
  font-family: "Instrument Serif", serif;
  font-style: italic;
  font-size: clamp(1.15rem, 2.4vw, 1.5rem);
  color: var(--ink);
}
.foot-social {
  margin-top: 1.4rem;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  column-gap: clamp(1.2rem, 3vw, 2.5rem);
  row-gap: 0.5rem;
}
/* The sideways padding is here and not on the two navs because one of these
   links is a single letter: it needs the width as well as the height. */
.foot-social a {
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink-muted);
  white-space: nowrap;
  padding: 0.22rem 0.5rem;
  margin: -0.22rem -0.5rem;
}
.foot-social a:hover { color: var(--ink); }
/* The byline is the footer proper, not a third row of the link block above it,
   so it sits a line clear of the social row rather than under it. */
.byline {
  margin-top: 2.4rem;
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* ---------- consent bar ---------- */
/* Shown once, on the first visit, and never again on that browser. It sits at
   the bottom rather than over the masthead, because the first thing a visitor
   came for is the photograph. */
/* `hidden` is a user-agent rule, `.consent` is an author rule, so display:flex
   below beats it and the attribute would do nothing at all. Stated explicitly
   here or the bar can never be dismissed. */
.consent[hidden] { display: none; }
.consent {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 40;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.75rem clamp(1rem, 3vw, 2rem);
  padding: 0.9rem clamp(1rem, 3vw, 2.5rem);
  background: var(--ground-2);
  border-top: 1px solid var(--hairline);
}
.consent p {
  margin: 0;
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--ink-muted);
  max-width: 60ch;
}
.consent__buttons { display: flex; gap: 0.6rem; flex-shrink: 0; }
.consent button {
  font: inherit;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.5rem 1.1rem;
  border-radius: 2px;
  cursor: pointer;
  background: none;
  border: 1px solid var(--hairline);
  color: var(--ink-muted);
}
.consent button:hover { color: var(--ink); border-color: var(--ink-muted); }
/* Both buttons are styled identically and neither is given the accent. The ICO
   checklist for consent mechanisms reads "Our consent mechanism makes it as
   easy to refuse consent as it is to accept", and its good-practice example is
   described as "equally prominent options to 'accept all' or 'reject all'".
   Emphasising either one fails that, so neither is emphasised.
   ico.org.uk/for-organisations/direct-marketing-and-privacy-and-electronic-communications/
   guidance-on-the-use-of-storage-and-access-technologies/how-do-we-manage-consent-in-practice/ */

/* ---------- lightbox caption strip ---------- */

.pswp__custom-caption {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: var(--lightbox-cap);
  padding: var(--space-md) var(--page-gutter) var(--space-md);
  font-size: var(--text-sm);
  pointer-events: none;
  transition: opacity var(--dur-short) var(--ease-out);
}
/* The strip carries the title and one row of controls, and nothing else, so
   the photograph keeps the height it had before the data block existed. The
   data block is the same one the image page shows, and it opens upward over
   the bottom of the image on demand rather than taking room from it. */
.pswp__custom-caption .cap-controls {
  display: flex;
  align-items: baseline;
  gap: var(--space-md);
  margin-top: var(--space-sm);
}
.pswp__custom-caption .cap-more {
  pointer-events: auto;
  padding: 0;
  background: none;
  border: 0;
  border-bottom: var(--rule-hair) solid var(--hairline);
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.pswp__custom-caption .cap-more:hover,
.pswp__custom-caption .cap-more[aria-expanded="true"] {
  color: var(--ink);
  border-bottom-color: var(--ink);
}
.pswp__custom-caption .cap-data {
  position: absolute;
  left: 0; right: 0;
  bottom: 100%;
  height: calc(var(--lightbox-details-below) * 1px);
  overflow-y: auto;
  pointer-events: auto;
  padding: 2rem var(--page-gutter) var(--space-md);
  border-top: var(--rule-hair) solid var(--hairline);
}
/* Top left, not top right: the lightbox draws its own next arrow centred on
   the right edge, and on a wide window the panel sits against that edge, so a
   close control there is a click away from paging the gallery by accident. */
.pswp__custom-caption .cap-close {
  position: absolute;
  top: var(--space-2xs); left: var(--page-gutter);
  padding: 0 0.25rem;
  background: none;
  border: 0;
  cursor: pointer;
  font-size: 1.25rem;
  line-height: 1.2;
  color: var(--ink-muted);
}
.pswp__custom-caption .cap-close:hover { color: var(--ink); }
.pswp__custom-caption .img-data > div {
  display: grid;
  grid-template-columns: 8.5rem 1fr;
  gap: 0.5rem;
  padding: 0.35rem 0;
  border-bottom: var(--rule-hair) solid var(--hairline);
}
.pswp__custom-caption .img-data dt {
  font-size: var(--text-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.pswp__custom-caption .img-data dd {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--ink);
}
@media (max-width: 759px) {
  .pswp__custom-caption .img-data > div { grid-template-columns: 1fr; gap: 0.1rem; }
}
/* the margin beside the image is wide enough to hold the panel */
@media (min-width: 900px) {
  :root { --lightbox-details-side: 320; }
  .pswp__custom-caption .cap-data {
    left: auto;
    width: calc(var(--lightbox-details-side) * 1px);
    height: auto;
    max-height: calc(100vh - var(--lightbox-cap) - 3rem);
    padding: 2rem var(--page-gutter) var(--space-md) var(--space-md);
    border-top: 0;
    border-left: var(--rule-hair) solid var(--hairline);
  }
  .pswp__custom-caption .cap-data .img-data > div {
    grid-template-columns: 1fr;
    gap: 0.1rem;
    padding: var(--space-xs) 0;
  }
  .pswp__custom-caption .cap-close { left: var(--space-md); }
}
/* zoomed in, the strip fades out and stops catching clicks with it */
.pswp__custom-caption.is-hidden { opacity: 0; }
.pswp__custom-caption.is-hidden * { pointer-events: none; }
.pswp__custom-caption b {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-base);
  margin-bottom: var(--space-2xs);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pswp__custom-caption .g-buy {
  pointer-events: auto;
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-accent);
  /* The rule under the text is the border; the browser default underline would
     draw a second line right beside it. */
  text-decoration: none;
  border-bottom: var(--rule-hair) solid var(--color-accent);
  white-space: nowrap;
}
/* folio serves Instrument Serif at 400 only; avoid a synthesised bold */
.pswp__custom-caption b { font-weight: 400; }

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