/* ---------- tokens ----------
   Black and white at full contrast, like a plot on paper; dusty pink is
   the one highlight, always a solid block with black text on it (where
   you are, what you're pointing at, a selection). */
:root {
  --bg:      #ffffff;
  --surface: #efefef;
  --fg:      #000000;
  --muted:   #4d4d4d;
  --line:    #000000;
  --pink:    #f0d3d6;
  --on-pink: #000000;

  /* one spacing rhythm for the whole page: each step about 1.6 times the
     last (8, 13, 21, 34, 55, 89, 144), so gaps relate to each other */
  --s1: 8px;
  --s2: 13px;
  --s3: 21px;
  --s4: 34px;
  --s5: 55px;
  --s6: 89px;
  --s7: 144px;
  /* the margin at each side grows with the screen; the content stops at
     --content and centres */
  --gutter: clamp(21px, 4vw, 55px);
  --content: 1376px;
  --measure: min(var(--content), 100% - 2 * var(--gutter));
  color-scheme: light;
  /* one face for everything, labels included: a serif made for reading
     on screens */
  --text: "Source Serif 4", "Iowan Old Style", Georgia, serif;
  /* three text sizes, and no others: small for numbers, captions and the
     footer; base for titles, labels and notes; reading for the about
     page, the email page and an opened piece's title */
  --t-small: 0.8125rem;  /* 13px */
  --t-base:  0.9375rem;  /* 15px */
  --t-read:  1.125rem;   /* 18px */
}


/* the pink highlight: a solid block, black text, edges that follow wrapped lines */
.hl {
  background: var(--pink);
  color: var(--on-pink);
}

/* ---------- base ---------- */
* { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  /* the lace header is measured before the rest of the page exists, so
     the scrollbar's room is kept from the start (where it takes any) */
  scrollbar-gutter: stable;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--text);
  font-size: var(--t-base);
  line-height: 1.65;
  font-feature-settings: "kern" 1;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow-x: hidden;
}

button { font: inherit; color: inherit; }

a { color: inherit; }

::selection { background: var(--pink); color: var(--on-pink); }

:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 3px;
  border-radius: 1px;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--bg);
  color: var(--fg);
  padding: 10px 16px;
  border: 1px solid var(--line);
}
.skip:focus { left: 16px; top: 16px; }

/* ---------- header ---------- */
.nameplate {
  width: 100%;
  padding: var(--s3) 0 0;
}

/* name on the left, pages on the right, a hairline under both: the
   letterhead every page shares */
/* name on the left, pages on the right, a light rule under both */
.nameplate-top {
  width: var(--measure);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px 28px;
  flex-wrap: wrap;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--surface);
}

/* the name, typed, until the header image is set; then the image */
.nameplate h1 {
  margin: 0;
  font-size: var(--t-read);
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  line-height: 1.2;
}
.nameplate h1.has-logo { line-height: 0; }
.nameplate h1 img {
  display: block;
  height: clamp(64px, 3.5rem + 2.4vw, 104px);
  width: auto;
  max-width: 100%;
  object-fit: contain;
}

/* nav and the icons sit on one line, with a hairline between them */
.top-right {
  display: flex;
  align-items: center;
  gap: 28px;
}

.nav {
  display: flex;
  gap: 12px;
}
.nav a {
  position: relative;
  padding: 3px 7px;
  font-size: var(--t-base);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--fg);
  text-decoration: none;
  transition: background-color 0.12s ease;
}
/* the pages are underlined, not highlighted: the pink block marks the
   section names, which aren't links */
.nav a:hover,
.nav a[aria-current="page"] {
  text-decoration: underline;
  text-decoration-color: var(--pink);
  text-decoration-thickness: 2px;
  text-underline-offset: 5px;
}
/* a fingertip-sized target around each small link, without moving it */
.nav a::after {
  content: "";
  position: absolute;
  inset: -12px -10px;
}

/* the header's height: until the lace is drawn (a moment, or longer on a
   slow connection) the typed header takes exactly the lace's height, so
   nothing moves when the lace swaps in. The lace picks its stitch size by
   the width of the window, so its height steps at these widths. They fit
   the current name, two tabs and three icons: if those change, main.js
   warns in the console (on localhost) which width needs a new value. */
:root { --lace-h: 100px; }
@media (min-width: 348px) { :root { --lace-h: 150px; } }
@media (min-width: 449px) { :root { --lace-h: 199px; } }
@media (min-width: 724px) { :root { --lace-h: 78px; } }
@media (min-width: 964px) { :root { --lace-h: 103px; } }
@media (min-width: 1205px) { :root { --lace-h: 129px; } }
.nameplate:not(.is-lace) .nameplate-top {
  min-height: var(--lace-h);
  justify-content: center;
  /* no rule under it: the lace that replaces it has none */
  padding-bottom: 0;
  border-bottom: 0;
}
/* the lace is normally drawn before the page shows (lace.js runs straight
   after the header), so the typed header waits unseen for its first two
   seconds, like a web font does; it only appears if the lace doesn't */
@keyframes typed-wait { from, to { visibility: hidden; } }
/* (it's a wait, not motion, so it stays with reduced motion too) */
.nameplate:not(.is-lace) .nameplate-top > * { animation: typed-wait 2s !important; }
/* below 724px the lace folds into three centred lines (the name, the tabs,
   the icons), and the typed header does the same */
@media (max-width: 723px) {
  .nameplate:not(.is-lace) .nameplate-top {
    align-items: center;
    gap: 8px;
  }
  .nameplate:not(.is-lace) .top-right {
    flex-direction: column;
    gap: 6px;
  }
  .nameplate:not(.is-lace) .nav { margin: 0; }
  .nameplate:not(.is-lace) .socials { margin: -7px 0; }
}
/* from 724px the lace is one short band, so the typed header keeps to one
   line too (name left, pages and icons right) to fit in it */
@media (min-width: 724px) {
  .nameplate:not(.is-lace) .nameplate-top {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

/* the lace header (main.js + filet.js): one band of black filet lace with
   the name, the page tabs and the socials in it. The canvas sits over each
   link's pink backing, so the pink shows through the openings and holes.
   The typed nav and icons are only there until the lace is drawn. */
.nameplate.is-lace .nameplate-top { display: block; border-bottom: 0; padding-bottom: 0; }
.nameplate.is-lace .top-right { display: none; }
.lace-box { position: relative; isolation: isolate; line-height: 0; }
.lace-box canvas { position: relative; display: block; }
.lace-box .hit { position: absolute; display: block; }
.lace-box .hit::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  transition: background-color 0.12s ease;
}
.lace-box .hit:hover::before { background: color-mix(in srgb, var(--pink) 70%, transparent); }
.lace-box .hit[aria-current="page"]::before { background: var(--pink); }
/* the name is a link home, but stays as it is under the pointer */
.lace-box .hit.home:hover::before { background: none; }
/* a fingertip-sized target round each small tab and icon, without moving it */
.lace-box .hit::after { content: ""; position: absolute; inset: -9px -3px; }
/* on a phone: the slim lace menu that drops in once the header scrolls away */
.lace-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 30;
  display: flex;
  justify-content: center;
  padding-top: env(safe-area-inset-top, 0px);
  transform: translateY(-120%);
  transition: transform 0.2s ease;
  pointer-events: none;
}
.lace-bar::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: env(safe-area-inset-top, 0px);
  background: var(--bg);
}
.lace-bar.show { transform: none; pointer-events: auto; }
.lace-backing { position: absolute; z-index: -2; background: var(--bg); }
@media (prefers-reduced-motion: reduce) { .lace-bar { transition: none; } }
/* the lace trim along the very bottom of the page */
.lace-trim { flex-shrink: 0; display: flex; justify-content: center; line-height: 0; }
.lace-trim canvas { display: block; }
body.has-trim footer { padding-bottom: var(--s3); }


/* a section's name, with a quiet fact on the right */
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 20px;
  flex-wrap: wrap;
  margin-bottom: var(--s4);
}
.section-head h2 {
  font-size: var(--t-base);
  font-weight: 500;
  letter-spacing: 0.01em;
  line-height: 1.3;
  margin: 0;
}


/* ---------- the wall ---------- */
main {
  position: relative;
  flex: 1 0 auto;
  width: 100%;
}

/* the work, and the plotting series in a sidebar beside it */
.rooms {
  width: var(--measure);
  margin: 0 auto;
  padding: var(--s5) 0 0;
}
#wall { min-width: 0; }

/* hung like a gallery wall: every piece keeps its artwork's proportions
   (--r, width / height), and the pieces in a row share one height. Each
   grows in proportion to its ratio, so a row fills the width without
   anything being cropped. */
.wall {
  --row: 250px;
  --frame: 0px;      /* nothing around the art; the layout still reads it */
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--s5) var(--s4);
}
/* soaks up the spare room on the last row, so a short row isn't blown up */
.wall::after { content: ""; flex: 999 1 0; }

/* once the script has hung a wall, every piece has a measured place */
.wall.hung {
  display: block;
  position: relative;
}
.wall.hung::after { display: none; }
.hung > .frame { position: absolute; flex: none; }

.frame {
  --r: 1;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
}
.wall .frame {
  flex: var(--r) 1 calc(var(--r) * var(--row));
  width: auto;
  min-width: 0;
}

/* the art itself, at its own proportions */
.frame-inner {
  position: relative;
  aspect-ratio: var(--r);
  background: var(--surface);
  overflow: hidden;
  transition: opacity 0.2s ease;
}
.frame-inner img,
.frame-inner video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.frame:hover .frame-inner { opacity: 0.85; }
/* the title waits until you point at a piece; it keeps its room, so the
   wall doesn't move. Touch screens can't point, so they always show it */
@media (hover: hover) {
  .frame-caption { opacity: 0; transition: opacity 0.2s ease; }
  .frame:hover .frame-caption,
  .frame:focus-visible .frame-caption { opacity: 1; }
}

/* placeholder drawings sit on a plain board */
.frame-inner.doodle {
  display: grid;
  place-items: center;
  padding: 22px;
}
.frame-inner svg {
  width: 58%;
  height: 58%;
  color: var(--muted);
}

/* the name, underneath */
.frame-caption { padding-top: var(--s2); }
.frame-title {
  display: inline;
  font-size: var(--t-base);
  font-weight: 400;
  line-height: 1.5;
}
.frame-sub {
  display: block;
  margin-top: 1px;
  color: var(--muted);
  font-size: var(--t-base);
  line-height: 1.4;
}

/* ---------- the plotting series ----------
   The current series, above the work: every day so far, ten to a row
   (five on phones), newest first. */
.plots { scroll-margin-top: 24px; }
/* the work comes after the series */
#wall { margin-top: var(--s6); }
#series[hidden] + #wall { margin-top: 0; }
.plots-head { display: block; margin-bottom: var(--s3); }
/* the series name moves to its own line as a whole rather than breaking */
#series-title { display: inline-block; }
.plots-head h2 {
  font-size: var(--t-base);
  font-weight: 500;
  letter-spacing: 0.01em;
  line-height: 1.3;
  margin: 0;
}
.series-intro {
  margin: var(--s1) 0 0;
  max-width: 70ch;
  color: var(--muted);
  font-size: var(--t-base);
}
.series-intro:empty { display: none; }

.days {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(10, minmax(0, 1fr));
  gap: var(--s3);
}
.day {
  position: relative;
  aspect-ratio: 1 / 1;
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-start;
  gap: 4px;
  padding: 8px;
  overflow: hidden;
  border: 0;
  font: inherit;
  font-size: var(--t-small);
  line-height: 1.3;
  text-align: left;
  font-variant-numeric: tabular-nums;
}
button.day {
  background: var(--surface);
  color: var(--fg);
  cursor: pointer;
  transition: outline-color 0.12s ease;
  outline: 2px solid transparent;
  outline-offset: 2px;
}
.day.has-image img,
.day.has-image video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.day-num { position: relative; letter-spacing: 0.04em; }
/* a day with a picture shows its number under the square instead */
.day.has-image .day-num { display: none; }
.day-caption {
  display: block;
  margin-top: var(--s1);
  font-size: var(--t-small);
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
}
.day-caption-theme { display: none; }
/* a day's number sits under it; point at it and its theme takes the
   number's place. Touch screens keep the number. The theme can be wider than its
   square, so it hangs under it without moving anything */
@media (hover: hover) {
  .days li { position: relative; }
  .day-caption { position: relative; min-height: 1.3em; }
  .day-caption-num { transition: opacity 0.2s ease; }
  .days li:hover .day-caption-num,
  .day:focus-visible + .day-caption .day-caption-num { opacity: 0; }
  .day-caption-theme {
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    z-index: 1;
    width: max-content;
    white-space: nowrap;
    padding-right: 8px;
    background: var(--bg);
    opacity: 0;
    transition: opacity 0.2s ease;
  }
  /* the last squares in the row hang theirs to the left instead */
  .days li:nth-child(10n) .day-caption-theme,
  .days li:nth-child(10n - 1) .day-caption-theme { left: auto; right: 0; padding: 0 0 0 8px; text-align: right; }
  .days li:hover .day-caption-theme,
  .day:focus-visible + .day-caption .day-caption-theme { opacity: 1; }
}
/* a narrow window has five to a row */
@media (hover: hover) and (max-width: 760px) {
  .days li:nth-child(5n) .day-caption-theme,
  .days li:nth-child(5n - 1) .day-caption-theme { left: auto; right: 0; padding: 0 0 0 8px; text-align: right; }
}
.day-concept { color: var(--muted); }

.wall-empty { color: var(--muted); }

/* ---------- about ---------- */
/* the text on the left, your photo (when there is one) on the right */
.about {
  width: var(--measure);
  margin: 0 auto;
  padding: var(--s5) 0 var(--s4);
  display: grid;
  /* the photo sits right beside the text, not out at the far edge */
  grid-template-columns: minmax(0, 60ch) minmax(240px, 560px);
  justify-content: start;
  gap: var(--s4) var(--s5);
  align-items: start;
}
.about-body { grid-column: 1; grid-row: 1; }
.about-portrait { grid-column: 2; grid-row: 1; }
/* no photo yet: the text starts at the left edge, in line with the wall */
.about:has(.about-portrait[hidden]) .about-body { grid-column: 1 / -1; }
/* the photo, whole, at its own proportions, with its caption under it */
.about-portrait { margin: 0; }
.about-portrait[hidden] { display: none; }
.about-portrait img,
.about-portrait video {
  display: block;
  width: 100%;
  height: auto;
  background: var(--surface);
  /* the same pink as the highlights, as a fine rule under the photo */
  border-bottom: 2px solid var(--pink);
}
.about-portrait figcaption {
  margin-top: 10px;
  color: var(--muted);
  font-size: var(--t-small);
  letter-spacing: 0.04em;
}
.about-text {
  max-width: 60ch;
  font-size: var(--t-read);
  line-height: 1.65;
  font-optical-sizing: auto;
}
/* links in the text: a fine underline, filling in pink on hover */
.about-text a {
  color: inherit;
  text-decoration: underline 1px var(--fg);
  text-underline-offset: 4px;
  transition: background-color 0.12s ease;
}
.about-text a:hover { background: var(--pink); color: var(--on-pink); }
.about-text a .ext-tail { white-space: nowrap; }
/* the new-tab arrow: small, raised, outside the underline */
.about-text a .ext {
  display: inline-block;
  margin-left: 0.12em;
  width: 0.55em;
  height: 0.55em;
  vertical-align: 0.55em;
  line-height: 0;
  text-decoration: none;
}
.about-text a .ext svg { display: block; width: 100%; height: 100%; }
.about-text p { margin: 0 0 1.1em; }
.about-text p:last-child { margin-bottom: 0; }

/* ---------- footer ---------- */
footer {
  position: relative;
  flex-shrink: 0;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px 28px;
  flex-wrap: wrap;
  /* the rule lines up with the content, like the header's */
  width: var(--measure);
  margin: var(--s6) auto 0;
  padding: 0 0 var(--s4);
}



.socials {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 0;
  margin: -7px -10px -7px 0;
  padding: 0;
}
.social {
  display: inline-grid;
  place-items: center;
  width: 40px;
  height: 44px;
  color: var(--fg);
  text-decoration: none;
  transition: color 0.15s ease;
}
.social-icon { display: block; width: 19px; height: 19px; }
.social-icon svg { display: block; width: 100%; height: 100%; }

/* visible to screen readers, not to eyes */
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.colophon {
  margin: 0;
  color: var(--fg);
  font-size: var(--t-small);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
/* the address stays as typed, so it reads (and copies) as an address */
.footer-email { text-transform: none; letter-spacing: 0.02em; }

/* ---------- the email page (a computer's envelope comes here) ---------- */
.email-me {
  width: var(--measure);
  margin: 0 auto;
  padding: var(--s6) 0 var(--s4);
}
.email-me-note {
  max-width: 40ch;
  /* a paragraph's gap, as on the about page, then the address */
  margin: 0 0 1.1em;
  font-size: var(--t-read);
  line-height: 1.65;
}
/* the copy icon beside the address; a tick and a word once it's copied */
.email-me-copy {
  flex: none;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: none;
  color: var(--fg);
  cursor: pointer;
}
.email-me-copy svg { width: 20px; height: 20px; }
.email-me-status { font-size: var(--t-base); color: var(--muted); }
.footer-email a { color: inherit; text-decoration: none; }
.footer-email a:hover { background: var(--pink); color: var(--on-pink); }
.email-me-address {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  /* the same size as the words round it, so its weight sets it apart */
  font-size: var(--t-read);
  font-weight: 600;
  line-height: 1.3;
  font-optical-sizing: auto;
  overflow-wrap: anywhere;
}

/* ---------- the viewer ---------- */
.viewer {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: grid;
  place-items: center;
  padding: 28px;
}
.viewer[hidden] { display: none; }

.viewer-backdrop {
  position: absolute;
  inset: 0;
  background: var(--bg);
  opacity: 0.97;
}

.viewer-panel {
  position: relative;
  width: min(1040px, 100%);
  max-height: calc(100dvh - 56px);
  overflow: auto;
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 44px;
  align-items: start;
}

.viewer-close {
  position: absolute;
  top: -5px;
  right: -5px;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  background: none;
  border: 0;
  color: var(--muted);
  cursor: pointer;
  z-index: 2;
  transition: color 0.15s ease;
}
.viewer-close svg { width: 15px; height: 15px; }
.viewer-close:hover { background: var(--pink); color: var(--on-pink); }

.viewer-media {
  display: grid;
  gap: 12px;
  min-width: 0;
}

.viewer-stage { position: relative; display: grid; min-width: 0; }
/* when a piece has several images: under the art, the thumbnails with an
   arrow either side, so nothing sits on the picture */
.viewer-pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
}
.viewer-pager[hidden] { display: none; }
.viewer-step {
  flex: none;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--fg);
  border-radius: 50%;
  background: var(--bg);
  color: var(--fg);
  cursor: pointer;
  transition: background-color 0.12s ease;
}
.viewer-step:hover { background: var(--pink); color: var(--on-pink); }
.viewer-step svg { width: 18px; height: 18px; }

/* the art at its own proportions, as large as the screen allows */
.viewer-art {
  display: grid;
  place-items: center;
  min-width: 0;
}
.viewer-art .frame-inner { aspect-ratio: auto; max-width: 100%; background: none; }
.viewer-art .frame-inner img,
.viewer-art .frame-inner video {
  max-width: 100%;
  max-height: calc(100dvh - 150px);
  width: auto;
  height: auto;
}
.viewer-art .frame-inner.doodle {
  width: min(460px, 70vw);
  aspect-ratio: 1 / 1;
  padding: 34px;
}
.viewer-art svg { width: 48%; height: 48%; color: var(--muted); }

/* pause / play, under a video */
.viewer-play {
  justify-self: center;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 44px;
  padding: 0 12px;
  background: none;
  border: 0;
  font-size: var(--t-small);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--fg);
  cursor: pointer;
  transition: color 0.15s ease;
}
.viewer-play[hidden] { display: none; }
.viewer-play:hover { background: var(--pink); color: var(--on-pink); }
.viewer-play svg { width: 13px; height: 13px; }
.viewer-play .icon-play,
.viewer-play[data-state="paused"] .icon-pause { display: none; }
.viewer-play[data-state="paused"] .icon-play { display: block; }

.viewer-thumbs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}
.viewer-thumb {
  position: relative;
  width: 72px;
  height: 72px;
  padding: 0;
  border: 0;
  background: var(--surface);
  cursor: pointer;
  opacity: 0.6;
  transition: opacity 0.15s ease;
}
.viewer-thumb:hover { opacity: 1; }
.viewer-thumb[aria-current="true"] {
  opacity: 1;
  outline: 2px solid var(--pink);
  outline-offset: 2px;
}
/* on phones, dots and "image 1 of 3" under the art stand in for the arrows */
.viewer-dots { display: none; }
.viewer-dot-row { display: flex; gap: 7px; }
.viewer-dot {
  width: 7px;
  height: 7px;
  border: 1px solid var(--fg);
  border-radius: 50%;
}
.viewer-dot.on { background: var(--fg); }
.viewer-dot-count { color: var(--muted); font-size: var(--t-small); }

.viewer-thumb img,
.viewer-thumb video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}

.viewer-text { padding-right: 46px; }
.viewer-text h2 {
  font-size: var(--t-read);
  font-weight: 500;
  letter-spacing: 0.01em;
  margin: 0;
  line-height: 1.3;
}
.viewer-year {
  color: var(--muted);
  font-size: var(--t-base);
  margin: 4px 0 20px;
}
.viewer-note {
  margin: 0 0 28px;
  font-size: var(--t-base);
  line-height: 1.6;
}
/* a blank line in the description is a new paragraph */
.viewer-note p { margin: 0; }
.viewer-note p + p { margin-top: 0.8em; }

/* back / next, in the plotting series only */
.viewer-nav {
  display: flex;
  align-items: center;
  gap: 22px;
  flex-wrap: wrap;
  border-top: 1px solid var(--line);
  padding-top: 18px;
}
.viewer-nav[hidden] { display: none; }
.nav-btn {
  background: none;
  border: 0;
  padding: 12px 8px;
  margin: -12px -8px;
  font-size: var(--t-small);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--fg);
  cursor: pointer;
}
/* a fine underline under the pointer, like the links in the text */
.nav-btn:hover { text-decoration: underline 1px var(--fg); text-underline-offset: 4px; }
/* the days read "Day 14", not capitals */
.viewer-nav .nav-btn { text-transform: none; font-size: var(--t-base); letter-spacing: 0.01em; }
/* the older day keeps to the right, even when there's no newer one */
#prev { margin-left: auto; }

/* tablets: two columns would squeeze the text beside the photo, so the
   photo goes under the text */
@media (max-width: 960px) {
  .about { grid-template-columns: minmax(0, 60ch); }
  .about-body { grid-column: 1; grid-row: 1; }
  .about-portrait { grid-column: 1; grid-row: 2; max-width: 480px; }
}

/* ---------- small screens ---------- */
@media (max-width: 760px) {
  .nameplate { padding: var(--s2) 0 0; }
  .nameplate-top {
    margin: 0 auto;
    padding-bottom: 14px;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }
  /* the highlight block's padding would push the text off the left edge */
  .nav { gap: 12px; margin-left: -7px; }
  .socials { margin-left: -10px; margin-right: 0; }
  .rooms { padding: var(--s4) 0 0; }
  .wall { --row: 230px; gap: var(--s4) var(--s3); }
  #wall { margin-top: var(--s5); }
  .days { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--s2); }
  .day { padding: 6px; }
  .day-concept { display: none; }
  .about {
    grid-template-columns: 1fr;
    gap: var(--s4);
    padding: var(--s4) 0 var(--s3);
  }
  /* one column: the text first, the photo after it */
  .about-body { grid-column: 1; grid-row: 1; }
  .about-portrait { grid-column: 1; grid-row: 2; max-width: 480px; }
  footer {
    margin-top: var(--s5);
    padding: var(--s3) 0 var(--s4);
    flex-direction: column;
    gap: 14px;
  }
  /* the open piece fits the screen exactly and nothing in it scrolls,
     either way: the text keeps its size and the art shrinks to the room
     that's left. Every touch is ours, so the page can't pan behind it */
  .viewer {
    padding: 20px;
    overflow: hidden;
    touch-action: none;
    overscroll-behavior: none;
  }
  .viewer-panel {
    height: 100%;
    max-height: none;
    overflow: visible;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 22px;
    /* the art spans the full width here, so the close button gets its own
       strip above it instead of sitting on the piece */
    padding-top: 40px;
  }
  .viewer-close { top: -4px; right: -10px; }
  .viewer-media {
    display: flex;
    flex-direction: column;
    flex: 1 1 0;
    min-height: 0;
  }
  /* the art fills the room left above the text and fits inside it.
     It's placed absolutely rather than sized in percentages of the
     flexible room: Safari can work those out as zero, and the picture
     then doesn't show at all */
  .viewer-stage { flex: 1 1 0; min-height: 0; position: relative; }
  .viewer-art,
  .viewer-art .frame-inner { position: absolute; inset: 0; }
  .viewer-art .frame-inner img,
  .viewer-art .frame-inner video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    object-fit: contain;
  }
  .viewer-art .frame-inner.doodle {
    display: grid;
    place-items: center;
    width: auto;
    aspect-ratio: auto;
    padding: 24px;
  }
  .viewer-play,
  .viewer-text { flex: none; }
  .viewer-text { padding-right: 0; }
  .viewer-note { margin-bottom: 0; }
  .viewer-nav { margin-top: 20px; }
  /* a swipe steps through a piece's images and the dots say where you are */
  .viewer-pager { display: none; }
  .viewer-dots.many {
    display: flex;
    flex: none;
    flex-direction: column;
    align-items: center;
    gap: 8px;
  }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
